From e4629cca511931ae184a8bd64da8775734666bc6 Mon Sep 17 00:00:00 2001 From: Ruben Ayrapetyan Date: Fri, 24 Oct 2014 19:15:31 +0400 Subject: [PATCH] Improving precision of number to zt-string conversion, adding search for the shortest representation of number during the conversion. --- Makefile.mk | 6 + src/libecmaobjects/ecma-globals.h | 4 +- src/libecmaobjects/ecma-helpers-conversion.c | 441 +++++++++++++------ tests/unit/test_number_to_string.c | 20 +- tests/unit/test_string_to_number.c | 16 +- 5 files changed, 326 insertions(+), 161 deletions(-) diff --git a/Makefile.mk b/Makefile.mk index 43e288bc4..e2983c978 100644 --- a/Makefile.mk +++ b/Makefile.mk @@ -160,6 +160,7 @@ else OPTION_LIBC := raw endif +# float64 mode ifeq ($(filter float64,$(TARGET_MODS)), float64) ifeq ($(OPTION_MCU),enable) $(error MCU target doesn\'t support float64) @@ -170,6 +171,11 @@ else OPTION_FLOAT64 := disable endif +# Enabling float64 mode for unittests +ifeq ($(filter-out $(TESTS_TARGET),$(TARGET_MODE)),) + OPTION_FLOAT64 := enable +endif + ifeq ($(filter sanitize,$(TARGET_MODS)), sanitize) ifeq ($(OPTION_LIBC),musl) $(error ASAN and LIBC_MUSL are mutually exclusive) diff --git a/src/libecmaobjects/ecma-globals.h b/src/libecmaobjects/ecma-globals.h index 1c967b29a..eb38e4ebc 100644 --- a/src/libecmaobjects/ecma-globals.h +++ b/src/libecmaobjects/ecma-globals.h @@ -527,7 +527,7 @@ typedef float ecma_number_t; /** * Maximum number of significant digits that ecma-number can store */ -#define ECMA_NUMBER_MAX_DIGITS (10u) +#define ECMA_NUMBER_MAX_DIGITS (9) #elif CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64 /** * Description of an ecma-number @@ -537,7 +537,7 @@ typedef double ecma_number_t; /** * Maximum number of significant digits that ecma-number can store */ -#define ECMA_NUMBER_MAX_DIGITS (18u) +#define ECMA_NUMBER_MAX_DIGITS (18) #endif /* CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64 */ /** diff --git a/src/libecmaobjects/ecma-helpers-conversion.c b/src/libecmaobjects/ecma-helpers-conversion.c index 7ce0251ee..e7d3f6633 100644 --- a/src/libecmaobjects/ecma-helpers-conversion.c +++ b/src/libecmaobjects/ecma-helpers-conversion.c @@ -78,19 +78,44 @@ uint64_var = (name[2] << 32u) | (name[1] + ((name[0] >> 31u) != 0 ? 1 : 0)); \ } +/** + * Copy middle and low parts of 96-bit integer to specified uint64_t variable + */ +#define ECMA_NUMBER_CONVERSION_96BIT_INTEGER_ROUND_MIDDLE_AND_LOW_TO_UINT64(name, uint64_var) \ +{ \ + ECMA_NUMBER_CONVERSION_96BIT_INTEGER_CHECK_PARTS_ARE_32BIT (name); \ + uint64_var = (name[1] << 32u) | (name[0]); \ +} + +/** + * Check if specified 96-bit integers are equal + */ +#define ECMA_NUMBER_CONVERSION_96BIT_INTEGER_ARE_EQUAL(name1, name2) \ + ((name1)[0] == (name2[0]) \ + && (name1)[1] == (name2[1]) \ + && (name1)[2] == (name2[2])) + /** * Check if bits [lowest_bit, 96) are zero */ -#define ECMA_NUMBER_CONVERSION_96BIT_INTEGER_IS_BIT_MASK_ZERO(name, lowest_bit) \ +#define ECMA_NUMBER_CONVERSION_96BIT_INTEGER_IS_HIGH_BIT_MASK_ZERO(name, lowest_bit) \ ((lowest_bit) >= 64 ? ((name[2] >> ((lowest_bit) - 64)) == 0) : \ ((lowest_bit) >= 32 ? (name[2] == 0 && ((name[1] >> ((lowest_bit) - 32)) == 0)) : \ (name[2] == 0 && name[1] == 0 && ((name[0] >> (lowest_bit)) == 0)))) +/** + * Check if bits [0, highest_bit] are zero + */ +#define ECMA_NUMBER_CONVERSION_96BIT_INTEGER_IS_LOW_BIT_MASK_ZERO(name, highest_bit) \ + ((highest_bit >= 64) ? (name[1] == 0 && name[0] == 0 && (((uint32_t) name[2] << (95 - (highest_bit))) == 0)) : \ + ((highest_bit >= 32) ? (name[0] == 0 && (((uint32_t) name[1] << (63 - (highest_bit))) == 0)) : \ + (((uint32_t) name[0] << (31 - (highest_bit))) == 0))) + /** * Check if 96-bit integer is zero */ #define ECMA_NUMBER_CONVERSION_96BIT_INTEGER_IS_ZERO(name) \ - ECMA_NUMBER_CONVERSION_96BIT_INTEGER_IS_BIT_MASK_ZERO (name, 0) + ECMA_NUMBER_CONVERSION_96BIT_INTEGER_IS_HIGH_BIT_MASK_ZERO (name, 0) /** * Shift 96-bit integer one bit left @@ -125,7 +150,23 @@ } /** - * Add to 96-bit integers + * Increment 96-bit integer + */ +#define ECMA_NUMBER_CONVERSION_96BIT_INTEGER_INC(name) \ +{ \ + ECMA_NUMBER_CONVERSION_96BIT_INTEGER_CHECK_PARTS_ARE_32BIT (name); \ + \ + name [0] += 1ull; \ + name [1] += (name [0] >> 32u); \ + name [0] = (uint32_t) name [0]; \ + name [2] += (name [1] >> 32u); \ + name [1] = (uint32_t) name [1]; \ + \ + ECMA_NUMBER_CONVERSION_96BIT_INTEGER_CHECK_PARTS_ARE_32BIT (name); \ +} + +/** + * Add 96-bit integer */ #define ECMA_NUMBER_CONVERSION_96BIT_INTEGER_ADD(name_add_to, name_to_add) \ { \ @@ -144,6 +185,28 @@ ECMA_NUMBER_CONVERSION_96BIT_INTEGER_CHECK_PARTS_ARE_32BIT (name_to_add); \ } +/** + * Multiply 96-bit integer by 10 + */ +#define ECMA_NUMBER_CONVERSION_96BIT_INTEGER_MUL_10(name) \ +{ \ + ECMA_NUMBER_CONVERSION_96BIT_INTEGER_CHECK_PARTS_ARE_32BIT (name); \ + \ + /* fraction_uint96 = (fraction_uint96 << 3) + (fraction_uint96 << 1) or fraction_uint96 *= 10 */ \ + ECMA_NUMBER_CONVERSION_96BIT_INTEGER_LEFT_SHIFT (name); \ + \ + ECMA_NUMBER_CONVERSION_96BIT_INTEGER (name ## _tmp); \ + \ + ECMA_NUMBER_CONVERSION_96BIT_INTEGER_COPY (name ## _tmp, name); \ + \ + ECMA_NUMBER_CONVERSION_96BIT_INTEGER_LEFT_SHIFT (name ## _tmp); \ + ECMA_NUMBER_CONVERSION_96BIT_INTEGER_LEFT_SHIFT (name ## _tmp); \ + \ + ECMA_NUMBER_CONVERSION_96BIT_INTEGER_ADD (name, name ## _tmp); \ + \ + ECMA_NUMBER_CONVERSION_96BIT_INTEGER_CHECK_PARTS_ARE_32BIT (name); \ +} + /** * Divide 96-bit integer by 10 */ @@ -507,9 +570,9 @@ ecma_zt_string_to_number (const ecma_char_t *str_p) /**< zero-terminated string 0ull); /* Normalizing mantissa */ - JERRY_ASSERT (ECMA_NUMBER_CONVERSION_96BIT_INTEGER_IS_BIT_MASK_ZERO (fraction_uint96, 92)); + JERRY_ASSERT (ECMA_NUMBER_CONVERSION_96BIT_INTEGER_IS_HIGH_BIT_MASK_ZERO (fraction_uint96, 92)); - while (ECMA_NUMBER_CONVERSION_96BIT_INTEGER_IS_BIT_MASK_ZERO (fraction_uint96, 91)) + while (ECMA_NUMBER_CONVERSION_96BIT_INTEGER_IS_HIGH_BIT_MASK_ZERO (fraction_uint96, 91)) { ECMA_NUMBER_CONVERSION_96BIT_INTEGER_LEFT_SHIFT (fraction_uint96); binary_exponent--; @@ -524,30 +587,20 @@ ecma_zt_string_to_number (const ecma_char_t *str_p) /**< zero-terminated string while (e > 0) { - JERRY_ASSERT (ECMA_NUMBER_CONVERSION_96BIT_INTEGER_IS_BIT_MASK_ZERO (fraction_uint96, 92)); + JERRY_ASSERT (ECMA_NUMBER_CONVERSION_96BIT_INTEGER_IS_HIGH_BIT_MASK_ZERO (fraction_uint96, 92)); - /* fraction_uint96 = (fraction_uint96 << 3) + (fraction_uint96 << 1) or fraction_uint96 *= 10 */ - ECMA_NUMBER_CONVERSION_96BIT_INTEGER_LEFT_SHIFT (fraction_uint96); - - ECMA_NUMBER_CONVERSION_96BIT_INTEGER (fraction_uint96_tmp); - - ECMA_NUMBER_CONVERSION_96BIT_INTEGER_COPY (fraction_uint96_tmp, fraction_uint96); - - ECMA_NUMBER_CONVERSION_96BIT_INTEGER_LEFT_SHIFT (fraction_uint96_tmp); - ECMA_NUMBER_CONVERSION_96BIT_INTEGER_LEFT_SHIFT (fraction_uint96_tmp); - - ECMA_NUMBER_CONVERSION_96BIT_INTEGER_ADD (fraction_uint96, fraction_uint96_tmp); + ECMA_NUMBER_CONVERSION_96BIT_INTEGER_MUL_10 (fraction_uint96); e--; /* Normalizing mantissa */ - while (!ECMA_NUMBER_CONVERSION_96BIT_INTEGER_IS_BIT_MASK_ZERO (fraction_uint96, 92)) + while (!ECMA_NUMBER_CONVERSION_96BIT_INTEGER_IS_HIGH_BIT_MASK_ZERO (fraction_uint96, 92)) { ECMA_NUMBER_CONVERSION_96BIT_INTEGER_RIGHT_SHIFT (fraction_uint96); binary_exponent++; } - while (ECMA_NUMBER_CONVERSION_96BIT_INTEGER_IS_BIT_MASK_ZERO (fraction_uint96, 91)) + while (ECMA_NUMBER_CONVERSION_96BIT_INTEGER_IS_HIGH_BIT_MASK_ZERO (fraction_uint96, 91)) { ECMA_NUMBER_CONVERSION_96BIT_INTEGER_LEFT_SHIFT (fraction_uint96); @@ -565,7 +618,7 @@ ecma_zt_string_to_number (const ecma_char_t *str_p) /**< zero-terminated string while (e > 0) { /* Denormalizing mantissa, moving highest 1 to 95-bit */ - while (ECMA_NUMBER_CONVERSION_96BIT_INTEGER_IS_BIT_MASK_ZERO (fraction_uint96, 95)) + while (ECMA_NUMBER_CONVERSION_96BIT_INTEGER_IS_HIGH_BIT_MASK_ZERO (fraction_uint96, 95)) { ECMA_NUMBER_CONVERSION_96BIT_INTEGER_LEFT_SHIFT (fraction_uint96); @@ -580,13 +633,13 @@ ecma_zt_string_to_number (const ecma_char_t *str_p) /**< zero-terminated string } /* Normalizing mantissa */ - while (!ECMA_NUMBER_CONVERSION_96BIT_INTEGER_IS_BIT_MASK_ZERO (fraction_uint96, 92)) + while (!ECMA_NUMBER_CONVERSION_96BIT_INTEGER_IS_HIGH_BIT_MASK_ZERO (fraction_uint96, 92)) { ECMA_NUMBER_CONVERSION_96BIT_INTEGER_RIGHT_SHIFT (fraction_uint96); binary_exponent++; } - while (ECMA_NUMBER_CONVERSION_96BIT_INTEGER_IS_BIT_MASK_ZERO (fraction_uint96, 91)) + while (ECMA_NUMBER_CONVERSION_96BIT_INTEGER_IS_HIGH_BIT_MASK_ZERO (fraction_uint96, 91)) { ECMA_NUMBER_CONVERSION_96BIT_INTEGER_LEFT_SHIFT (fraction_uint96); @@ -597,20 +650,20 @@ ecma_zt_string_to_number (const ecma_char_t *str_p) /**< zero-terminated string } JERRY_ASSERT (!ECMA_NUMBER_CONVERSION_96BIT_INTEGER_IS_ZERO (fraction_uint96)); - JERRY_ASSERT (ECMA_NUMBER_CONVERSION_96BIT_INTEGER_IS_BIT_MASK_ZERO (fraction_uint96, 92)); + JERRY_ASSERT (ECMA_NUMBER_CONVERSION_96BIT_INTEGER_IS_HIGH_BIT_MASK_ZERO (fraction_uint96, 92)); /* * Preparing mantissa for conversion to 52-bit representation, converting it to: * * |12 zero bits|84 mantissa bits| */ - while (!ECMA_NUMBER_CONVERSION_96BIT_INTEGER_IS_BIT_MASK_ZERO (fraction_uint96, 84 + 1)) + while (!ECMA_NUMBER_CONVERSION_96BIT_INTEGER_IS_HIGH_BIT_MASK_ZERO (fraction_uint96, 84 + 1)) { ECMA_NUMBER_CONVERSION_96BIT_INTEGER_RIGHT_SHIFT (fraction_uint96); binary_exponent++; } - while (ECMA_NUMBER_CONVERSION_96BIT_INTEGER_IS_BIT_MASK_ZERO (fraction_uint96, 84)) + while (ECMA_NUMBER_CONVERSION_96BIT_INTEGER_IS_HIGH_BIT_MASK_ZERO (fraction_uint96, 84)) { ECMA_NUMBER_CONVERSION_96BIT_INTEGER_LEFT_SHIFT (fraction_uint96); @@ -619,7 +672,7 @@ ecma_zt_string_to_number (const ecma_char_t *str_p) /**< zero-terminated string JERRY_ASSERT (!ECMA_NUMBER_CONVERSION_96BIT_INTEGER_IS_ZERO (fraction_uint96)); } - JERRY_ASSERT (ECMA_NUMBER_CONVERSION_96BIT_INTEGER_IS_BIT_MASK_ZERO (fraction_uint96, 84 + 1)); + JERRY_ASSERT (ECMA_NUMBER_CONVERSION_96BIT_INTEGER_IS_HIGH_BIT_MASK_ZERO (fraction_uint96, 84 + 1)); ECMA_NUMBER_CONVERSION_96BIT_INTEGER_ROUND_HIGH_AND_MIDDLE_TO_UINT64 (fraction_uint96, fraction_uint64); @@ -740,6 +793,209 @@ ecma_number_to_int32 (ecma_number_t value) /**< unsigned 32-bit integer value */ return (int32_t) value; } /* ecma_number_to_int32 */ +/** + * Calculate s, n and k parameters for specified ecma-number according to ECMA-262 v5, 9.8.1, item 5 + */ +static void +ecma_number_to_zt_string_calc_number_params (ecma_number_t num, /**< ecma-number */ + uint64_t *out_digits_p, /**< out: digits */ + int32_t *out_digits_num_p, /**< out: number of digits */ + int32_t *out_decimal_exp_p) /**< out: decimal exponent */ +{ + ECMA_NUMBER_CONVERSION_96BIT_INTEGER (fraction_uint96); + +#if CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT32 + uint32_t s[2]; +#elif CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64 + uint64_t s[2]; +#endif /* CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64 */ + int32_t k[2]; + int32_t n[2]; + + for (uint32_t i = 0; + i <= 1; + i++) + { + uint64_t fraction_uint64; + int32_t binary_exponent; + int32_t dot_shift; + int32_t decimal_exp = 0; + + dot_shift = ecma_number_get_fraction_and_exponent (num, &fraction_uint64, &binary_exponent); + + binary_exponent -= dot_shift; + + JERRY_ASSERT (fraction_uint64 != 0); + + if (i == 0) + { + /* Lowest binary fraction that should round to fraction_uint64 */ + ECMA_NUMBER_CONVERSION_96BIT_INTEGER_INIT (fraction_uint96, + (fraction_uint64 - 1ull) >> 60u, + ((fraction_uint64 - 1ull) << 4u) >> 32u, + ((fraction_uint64 - 1ull) << 36u) >> 32u | 0x8u); + } + else + { + /* Highest binary fraction that should round to fraction_uint64 */ + ECMA_NUMBER_CONVERSION_96BIT_INTEGER_INIT (fraction_uint96, + (fraction_uint64) >> 60u, + ((fraction_uint64) << 4u) >> 32u, + ((fraction_uint64) << 36u) >> 32u | 0x7u); + } + + binary_exponent -= 4; + + /* Converting binary exponent to decimal exponent */ + if (binary_exponent > 0) + { + while (binary_exponent > 0) + { + if (!ECMA_NUMBER_CONVERSION_96BIT_INTEGER_IS_HIGH_BIT_MASK_ZERO (fraction_uint96, 92)) + { + ECMA_NUMBER_CONVERSION_96BIT_INTEGER_INC (fraction_uint96); + ECMA_NUMBER_CONVERSION_96BIT_INTEGER_RIGHT_SHIFT (fraction_uint96); + binary_exponent++; + } + else + { + ECMA_NUMBER_CONVERSION_96BIT_INTEGER (fraction_uint96_tmp); + ECMA_NUMBER_CONVERSION_96BIT_INTEGER_COPY (fraction_uint96_tmp, fraction_uint96); + ECMA_NUMBER_CONVERSION_96BIT_INTEGER_DIV_10 (fraction_uint96_tmp); + ECMA_NUMBER_CONVERSION_96BIT_INTEGER_MUL_10 (fraction_uint96_tmp); + + if (!ECMA_NUMBER_CONVERSION_96BIT_INTEGER_ARE_EQUAL (fraction_uint96, fraction_uint96_tmp) + && ECMA_NUMBER_CONVERSION_96BIT_INTEGER_IS_HIGH_BIT_MASK_ZERO (fraction_uint96, 91)) + { + ECMA_NUMBER_CONVERSION_96BIT_INTEGER_LEFT_SHIFT (fraction_uint96); + binary_exponent--; + } + else + { + ECMA_NUMBER_CONVERSION_96BIT_INTEGER_DIV_10 (fraction_uint96); + decimal_exp++; + } + } + } + } + else if (binary_exponent < 0) + { + while (binary_exponent < 0) + { + if (ECMA_NUMBER_CONVERSION_96BIT_INTEGER_IS_LOW_BIT_MASK_ZERO (fraction_uint96, 0) + || !ECMA_NUMBER_CONVERSION_96BIT_INTEGER_IS_HIGH_BIT_MASK_ZERO (fraction_uint96, 92)) + { + ECMA_NUMBER_CONVERSION_96BIT_INTEGER_RIGHT_SHIFT (fraction_uint96); + + binary_exponent++; + } + else + { + ECMA_NUMBER_CONVERSION_96BIT_INTEGER_MUL_10 (fraction_uint96); + + decimal_exp--; + } + } + } + +#if CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64 + uint64_t digits, t; + + /* While fraction doesn't fit to 64-bit integer, divide it by 10 + and simultaneously increment decimal exponent */ + while (!ECMA_NUMBER_CONVERSION_96BIT_INTEGER_IS_HIGH_BIT_MASK_ZERO (fraction_uint96, 64)) + { + ECMA_NUMBER_CONVERSION_96BIT_INTEGER_DIV_10 (fraction_uint96); + decimal_exp++; + } +#elif CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT32 + uint32_t digits, t; + + while (!ECMA_NUMBER_CONVERSION_96BIT_INTEGER_IS_HIGH_BIT_MASK_ZERO (fraction_uint96, 32)) + { + ECMA_NUMBER_CONVERSION_96BIT_INTEGER_DIV_10 (fraction_uint96); + decimal_exp++; + } +#endif /* CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT32 */ + + uint64_t digits_uint64; + int32_t digits_num = 0; + + ECMA_NUMBER_CONVERSION_96BIT_INTEGER_ROUND_MIDDLE_AND_LOW_TO_UINT64 (fraction_uint96, digits_uint64); + +#if CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64 + digits = digits_uint64; +#elif CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT32 + digits = (uint32_t) digits_uint64; + + JERRY_ASSERT (digits == digits_uint64); +#endif /* CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT32 */ + + /* Calculate number of digits in the number */ + t = digits; + while (t != 0) + { + if (digits_num < ECMA_NUMBER_MAX_DIGITS) + { + digits_num++; + } + else + { + if (t < 10) + { + digits += 5; + } + + digits /= 10; + } + + t /= 10; + + decimal_exp++; + } + + /* Saving bound values */ + s[i] = digits; + k[i] = digits_num; + n[i] = decimal_exp; + } + + /* Making bound values' digit sets to be of one length */ + for (uint32_t i = 0; i <= 1; i++) + { + while (n[i] - k[i] > n[1 - i] - k[1 - i]) + { + JERRY_ASSERT (s[i] * 10 > s[i]); + + s[i] *= 10; + k[i]++; + } + } + + JERRY_ASSERT (s[1] > s[0]); + + while (s[0] / 10 != s[1] / 10) + { + s[0] /= 10; + s[1] /= 10; + k[0]--; + k[1]--; + } + + /* Rounding up */ + if (k[0] == k[1]) + { + *out_digits_p = (s[0] + s[1] + 1) / 2; + } + else + { + *out_digits_p = s[1]; + } + + *out_digits_num_p = k[1]; + *out_decimal_exp_p = n[1]; +} /* ecma_number_to_zt_string_calc_number_params */ + /** * Convert ecma-number to zero-terminated string * @@ -757,8 +1013,6 @@ ecma_number_to_zt_string (ecma_number_t num, /**< ecma-number */ ecma_char_t *buffer_p, /**< buffer for zt-string */ ssize_t buffer_size) /**< size of buffer */ { - FIXME (Conversion precision); - const ecma_char_t digits[10] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; const ecma_char_t e_chars [2] = { 'e', 'E' }; const ecma_char_t plus_char = '+'; @@ -801,14 +1055,6 @@ ecma_number_to_zt_string (ecma_number_t num, /**< ecma-number */ else { // 5. -#if CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT32 -#define LL_T uint32_t -#define LL_MAX_DIGITS 10 -#elif CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64 -#define LL_T uint64_t -#define LL_MAX_DIGITS 18 -#endif /* CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64 */ - uint32_t num_uint32 = ecma_number_to_uint32 (num); if (ecma_uint32_to_number (num_uint32) == num) { @@ -817,116 +1063,29 @@ ecma_number_to_zt_string (ecma_number_t num, /**< ecma-number */ else { uint64_t fraction_uint64; - LL_T fraction; - int32_t exponent; - int32_t dot_shift; - int32_t decimal_exp = 0; + int32_t binary_exponent; - dot_shift = ecma_number_get_fraction_and_exponent (num, &fraction_uint64, &exponent); + ecma_number_get_fraction_and_exponent (num, &fraction_uint64, &binary_exponent); - fraction = (LL_T) fraction_uint64; - JERRY_ASSERT (fraction == fraction_uint64); - - if (exponent != 0) - { - ecma_number_t t = 1.0f; - bool do_divide; - - if (exponent < 0) - { - do_divide = true; - - while (exponent <= 0) - { - t *= 2.0f; - exponent++; - - if (t >= 10.0f) - { - t /= 10.0f; - decimal_exp--; - } - - JERRY_ASSERT (t < 10.0f); - } - - while (t > 1.0f) - { - exponent--; - t /= 2.0f; - } - } - else - { - do_divide = false; - - while (exponent >= 0) - { - t *= 2.0f; - exponent--; - - if (t >= 10.0f) - { - t /= 10.0f; - decimal_exp++; - } - - JERRY_ASSERT (t < 10.0f); - } - - while (t > 2.0f) - { - exponent++; - t /= 2.0f; - } - } - - if (do_divide) - { - fraction = (LL_T) ((ecma_number_t) fraction / t); - } - else - { - fraction = (LL_T) ((ecma_number_t) fraction * t); - } - } - - LL_T s; + /* mantissa */ + uint64_t s_uint64; + /* decimal exponent */ int32_t n; + /* number of digits in k */ int32_t k; - if (exponent > 0) - { - fraction <<= exponent; - } - else - { - fraction >>= -exponent; - } + ecma_number_to_zt_string_calc_number_params (num, + &s_uint64, + &k, + &n); - const int32_t int_part_shift = dot_shift; - const LL_T frac_part_mask = ((((LL_T)1) << int_part_shift) - 1); +#if CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64 + uint64_t s = s_uint64; +#elif CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT32 + uint32_t s = (uint32_t) s_uint64; - LL_T int_part = fraction >> int_part_shift; - LL_T frac_part = fraction & frac_part_mask; - - s = int_part; - k = 1; - n = decimal_exp + 1; - - JERRY_ASSERT (int_part < 10); - - while (k < LL_MAX_DIGITS - && frac_part != 0) - { - frac_part *= 10; - - LL_T new_frac_part = frac_part & frac_part_mask; - LL_T digit = (frac_part - new_frac_part) >> int_part_shift; - s = s * 10 + digit; - k++; - frac_part = new_frac_part; - } + JERRY_ASSERT (s == s_uint64); +#endif /* CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT32 */ // 6. if (k <= n && n <= 21) @@ -969,7 +1128,7 @@ ecma_number_to_zt_string (ecma_number_t num, /**< ecma-number */ s /= 10; } } - else if (-6 <= n && n <= 0) + else if (-6 < n && n <= 0) { // 8. dst_p += k - n + 1 + 1; @@ -1039,7 +1198,7 @@ ecma_number_to_zt_string (ecma_number_t num, /**< ecma-number */ { t_mod /= 10; - JERRY_ASSERT (t_mod != 0); + JERRY_ASSERT (t != 0); } while (t_mod != 0) diff --git a/tests/unit/test_number_to_string.c b/tests/unit/test_number_to_string.c index a62e684d5..21a267a06 100644 --- a/tests/unit/test_number_to_string.c +++ b/tests/unit/test_number_to_string.c @@ -32,8 +32,8 @@ main( int __unused argc, (const ecma_char_t*) "1", (const ecma_char_t*) "0.5", (const ecma_char_t*) "12345", - (const ecma_char_t*) "12345.12209", - (const ecma_char_t*) "1.401298403e-45", + (const ecma_char_t*) "12345.123", + (const ecma_char_t*) "1e-45", (const ecma_char_t*) "-2.5e+38", (const ecma_char_t*) "NaN", (const ecma_char_t*) "Infinity", @@ -44,17 +44,17 @@ main( int __unused argc, const ecma_number_t nums[] = { - 1.0f, - 0.5f, - 12345.0f, - 12345.123f, - 1.0e-45f, - -2.5e+38f, + 1.0, + 0.5, + 12345.0, + 12345.123, + 1.0e-45, + -2.5e+38, NAN, INFINITY, -INFINITY, - +0.0f, - -0.0f + +0.0, + -0.0 }; for (uint32_t i = 0; diff --git a/tests/unit/test_string_to_number.c b/tests/unit/test_string_to_number.c index 208e5809a..d45e51304 100644 --- a/tests/unit/test_string_to_number.c +++ b/tests/unit/test_string_to_number.c @@ -51,12 +51,12 @@ main( int __unused argc, const ecma_number_t nums[] = { - 1.0f, - 0.5f, - 12345.0f, - 1.0e-45f, - -2.5e+38f, - -2.5e+38f, + 1.0, + 0.5, + 12345.0, + 1.0e-45, + -2.5e+38, + -2.5e+38, NAN, NAN, NAN, @@ -67,8 +67,8 @@ main( int __unused argc, NAN, INFINITY, -INFINITY, - +0.0f, - -0.0f + +0.0, + -0.0 }; for (uint32_t i = 0;