/**
 * Errol0 double to ASCII conversion, guaranteed correct but possibly not optimal.
 *
 * @return digits
 */
inline uint64_t __attr_always_inline___
ecma_errol0_dtoa (ecma_number_t val, /**< ecma number */
                  int32_t *num_of_digits_p, /**< [out] number of digits */
                  int32_t *exp_p) /**< [out] exponent */
{
  uint64_t digits = 0u;
  int32_t num_of_digits = 0;
  double power_of_10 = 1.0;
  int32_t exp = 1;

  /* normalize the midpoint */
  ecma_high_prec_t mid;

  mid.value = val;
  mid.offset = 0.0;

  while (((mid.value > 10.0) || ((mid.value == 10.0) && (mid.offset >= 0.0))) && (exp < 308))
  {
    exp++;
    ecma_divide_high_prec_by_10 (&mid);
    power_of_10 /= 10.0;
  }

  while (((mid.value < 1.0) || ((mid.value == 1.0) && (mid.offset < 0.0))) && (exp > -307))
  {
    exp--;
    ecma_multiply_high_prec_by_10 (&mid);
    power_of_10 *= 10.0;
  }

  ecma_high_prec_t high_bound, low_bound;

  high_bound.value = mid.value;
  high_bound.offset = mid.offset + (ECMA_NEXT_FLOAT (val) - val) * power_of_10 / (2.0 + ERROL0_EPSILON);
  low_bound.value = mid.value;
  low_bound.offset = mid.offset + (ECMA_PREV_FLOAT (val) - val) * power_of_10 / (2.0 + ERROL0_EPSILON);

  ecma_normalize_high_prec_data (&high_bound);
  ecma_normalize_high_prec_data (&low_bound);

  /* normalized boundaries */

  while (high_bound.value > 10.0 || (high_bound.value == 10.0 && (high_bound.offset >= 0.0)))
  {
    exp++;
    ecma_divide_high_prec_by_10 (&high_bound);
    ecma_divide_high_prec_by_10 (&low_bound);
  }

  while (high_bound.value < 1.0 || (high_bound.value == 1.0 && (high_bound.offset < 0.0)))
  {
    exp--;
    ecma_multiply_high_prec_by_10 (&high_bound);
    ecma_multiply_high_prec_by_10 (&low_bound);
  }

  /* digit generation */

  while (high_bound.value != 0.0 || high_bound.offset != 0.0)
  {
    uint8_t high_digit = (uint8_t) high_bound.value;

    if ((high_bound.value == high_digit) && (high_bound.offset < 0))
    {
      high_digit = (uint8_t) (high_digit - 1u);
    }

    uint8_t low_digit = (uint8_t) low_bound.value;

    if ((low_bound.value == low_digit) && (low_bound.offset < 0))
    {
      low_digit = (uint8_t) (low_digit - 1u);
    }

    if (low_digit != high_digit)
    {
      break;
    }

    digits *= 10;
    digits += (uint64_t) high_digit;
    num_of_digits++;

    high_bound.value -= high_digit;
    ecma_multiply_high_prec_by_10 (&high_bound);

    low_bound.value -= low_digit;
    ecma_multiply_high_prec_by_10 (&low_bound);
  }

  double mdig = (high_bound.value + low_bound.value) / 2.0 + 0.5;

  *num_of_digits_p = num_of_digits + 1;
  *exp_p = exp;
  digits *= 10;

  return digits + (uint64_t) mdig;
} /* ecma_errol0_dtoa */
/**
 * Errol0 double to ASCII conversion, guaranteed correct but possibly not optimal.
 *
 * @return number of generated digits
 */
inline lit_utf8_size_t __attr_always_inline___
ecma_errol0_dtoa (double val, /**< ecma number */
                  lit_utf8_byte_t *buffer_p, /**< buffer to generate digits into */
                  int32_t *exp_p) /**< [out] exponent */
{
  double power_of_10 = 1.0;
  int32_t exp = 1;

  /* normalize the midpoint */
  ecma_high_prec_t mid;

  mid.value = val;
  mid.offset = 0.0;

  while (((mid.value > 10.0) || ((mid.value == 10.0) && (mid.offset >= 0.0))) && (exp < 308))
  {
    exp++;
    ecma_divide_high_prec_by_10 (&mid);
    power_of_10 /= 10.0;
  }

  while (((mid.value < 1.0) || ((mid.value == 1.0) && (mid.offset < 0.0))) && (exp > -307))
  {
    exp--;
    ecma_multiply_high_prec_by_10 (&mid);
    power_of_10 *= 10.0;
  }

  ecma_high_prec_t high_bound, low_bound;

  high_bound.value = mid.value;
  high_bound.offset = mid.offset;

  if (ECMA_NEXT_FLOAT (val) != INFINITY)
  {
    high_bound.offset += (ECMA_NEXT_FLOAT (val) - val) * power_of_10 / (2.0 + ERROL0_EPSILON);
  }

  low_bound.value = mid.value;
  low_bound.offset = mid.offset + (ECMA_PREV_FLOAT (val) - val) * power_of_10 / (2.0 + ERROL0_EPSILON);

  ecma_normalize_high_prec_data (&high_bound);
  ecma_normalize_high_prec_data (&low_bound);

  /* normalized boundaries */

  while (high_bound.value > 10.0 || (high_bound.value == 10.0 && (high_bound.offset >= 0.0)))
  {
    exp++;
    ecma_divide_high_prec_by_10 (&high_bound);
    ecma_divide_high_prec_by_10 (&low_bound);
  }

  while (high_bound.value < 1.0 || (high_bound.value == 1.0 && (high_bound.offset < 0.0)))
  {
    exp--;
    ecma_multiply_high_prec_by_10 (&high_bound);
    ecma_multiply_high_prec_by_10 (&low_bound);
  }

  /* digit generation */

  lit_utf8_byte_t *dst_p = buffer_p;

  while (high_bound.value != 0.0 || high_bound.offset != 0.0)
  {
    uint8_t high_digit = (uint8_t) high_bound.value;

    if ((high_bound.value == high_digit) && (high_bound.offset < 0))
    {
      high_digit = (uint8_t) (high_digit - 1u);
    }

    uint8_t low_digit = (uint8_t) low_bound.value;

    if ((low_bound.value == low_digit) && (low_bound.offset < 0))
    {
      low_digit = (uint8_t) (low_digit - 1u);
    }

    if (low_digit != high_digit)
    {
      break;
    }

    *dst_p++ = (lit_utf8_byte_t) ('0' + high_digit);

    high_bound.value -= high_digit;
    ecma_multiply_high_prec_by_10 (&high_bound);

    low_bound.value -= low_digit;
    ecma_multiply_high_prec_by_10 (&low_bound);
  }

  double mdig = (high_bound.value + low_bound.value) / 2.0 + 0.5;
  *dst_p++ = (lit_utf8_byte_t) ('0' + (uint8_t) mdig);

  *exp_p = exp;

  return (lit_utf8_size_t) (dst_p - buffer_p);
} /* ecma_errol0_dtoa */