diff --git a/src/libecmaobjects/ecma-globals.h b/src/libecmaobjects/ecma-globals.h index 2ac6c58c6..c9a4e8a47 100644 --- a/src/libecmaobjects/ecma-globals.h +++ b/src/libecmaobjects/ecma-globals.h @@ -525,11 +525,21 @@ typedef uint16_t ecma_char_t; * Description of an ecma-number */ typedef float ecma_number_t; + +/** + * Maximum number of significant digits that ecma-number can store + */ +#define ECMA_NUMBER_MAX_DIGITS (10u) #elif defined (CONFIG_ECMA_NUMBER_FLOAT64) /** * Description of an ecma-number */ typedef double ecma_number_t; + +/** + * Maximum number of significant digits that ecma-number can store + */ +#define ECMA_NUMBER_MAX_DIGITS (18u) #else /* !CONFIG_ECMA_NUMBER_FLOAT32 && !CONFIG_ECMA_NUMBER_FLOAT64 */ #error "!CONFIG_ECMA_NUMBER_FLOAT32 && !CONFIG_ECMA_NUMBER_FLOAT64" #endif /* !CONFIG_ECMA_NUMBER_FLOAT32 && !CONFIG_ECMA_NUMBER_FLOAT64 */ diff --git a/src/libecmaobjects/ecma-helpers-conversion.c b/src/libecmaobjects/ecma-helpers-conversion.c index 42e00228a..1e2b8a8d6 100644 --- a/src/libecmaobjects/ecma-helpers-conversion.c +++ b/src/libecmaobjects/ecma-helpers-conversion.c @@ -24,6 +24,190 @@ #include "ecma-helpers.h" #include "jerry-libc.h" +/* + * \addtogroup ecmahelpersbigintegers Helpers for operations intermediate 96-bit integers + * @{ + */ + +/** + * Check that parts of 96-bit integer are 32-bit. + */ +#define ECMA_NUMBER_CONVERSION_96BIT_INTEGER_CHECK_PARTS_ARE_32BIT(name) \ +{ \ + JERRY_ASSERT (name[0] == (uint32_t) name[0]); \ + JERRY_ASSERT (name[1] == (uint32_t) name[1]); \ + JERRY_ASSERT (name[2] == (uint32_t) name[2]); \ +} + +/** + * Declare 96-bit integer. + */ +#define ECMA_NUMBER_CONVERSION_96BIT_INTEGER(name) uint64_t name[3] = { 0, 0, 0 } + +/** + * Initialize 96-bit integer with given 32-bit parts + */ +#define ECMA_NUMBER_CONVERSION_96BIT_INTEGER_INIT(name, high, mid, low) \ +{ \ + name[2] = high; \ + name[1] = mid; \ + name[0] = low; \ + \ + ECMA_NUMBER_CONVERSION_96BIT_INTEGER_CHECK_PARTS_ARE_32BIT (name); \ +} + +/** + * Copy specified 96-bit integer + */ +#define ECMA_NUMBER_CONVERSION_96BIT_INTEGER_COPY(name_copy_to, name_copy_from) \ +{ \ + ECMA_NUMBER_CONVERSION_96BIT_INTEGER_CHECK_PARTS_ARE_32BIT (name_copy_to); \ + ECMA_NUMBER_CONVERSION_96BIT_INTEGER_CHECK_PARTS_ARE_32BIT (name_copy_from); \ + \ + name_copy_to[0] = name_copy_from [0]; \ + name_copy_to[1] = name_copy_from [1]; \ + name_copy_to[2] = name_copy_from [2]; \ +} + +/** + * Copy high and middle parts of 96-bit integer to specified uint64_t variable + */ +#define ECMA_NUMBER_CONVERSION_96BIT_INTEGER_ROUND_HIGH_AND_MIDDLE_TO_UINT64(name, uint64_var) \ +{ \ + ECMA_NUMBER_CONVERSION_96BIT_INTEGER_CHECK_PARTS_ARE_32BIT (name); \ + uint64_var = (name[2] << 32u) | (name[1] + ((name[0] >> 31u) != 0 ? 1 : 0)); \ +} + +/** + * Check if bits [lowest_bit, 96) are zero + */ +#define ECMA_NUMBER_CONVERSION_96BIT_INTEGER_IS_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 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) + +/** + * Shift 96-bit integer one bit left + */ +#define ECMA_NUMBER_CONVERSION_96BIT_INTEGER_LEFT_SHIFT(name) \ +{ \ + ECMA_NUMBER_CONVERSION_96BIT_INTEGER_CHECK_PARTS_ARE_32BIT (name); \ + \ + name[2] = (uint32_t) (name[2] << 1u); \ + name[2] |= name[1] >> 31u; \ + name[1] = (uint32_t) (name[1] << 1u); \ + name[1] |= name[0] >> 31u; \ + name[0] = (uint32_t) (name[0] << 1u); \ + \ + ECMA_NUMBER_CONVERSION_96BIT_INTEGER_CHECK_PARTS_ARE_32BIT (name); \ +} + +/** + * Shift 96-bit integer one bit right + */ +#define ECMA_NUMBER_CONVERSION_96BIT_INTEGER_RIGHT_SHIFT(name) \ +{ \ + ECMA_NUMBER_CONVERSION_96BIT_INTEGER_CHECK_PARTS_ARE_32BIT (name); \ + \ + name[0] >>= 1u; \ + name[0] |= (uint32_t) (name[1] << 31u); \ + name[1] >>= 1u; \ + name[1] |= (uint32_t) (name[2] << 31u); \ + name[2] >>= 1u; \ + \ + ECMA_NUMBER_CONVERSION_96BIT_INTEGER_CHECK_PARTS_ARE_32BIT (name); \ +} + +/** + * Add to 96-bit integers + */ +#define ECMA_NUMBER_CONVERSION_96BIT_INTEGER_ADD(name_add_to, name_to_add) \ +{ \ + ECMA_NUMBER_CONVERSION_96BIT_INTEGER_CHECK_PARTS_ARE_32BIT (name_add_to); \ + ECMA_NUMBER_CONVERSION_96BIT_INTEGER_CHECK_PARTS_ARE_32BIT (name_to_add); \ + \ + name_add_to [0] += name_to_add [0]; \ + name_add_to [1] += name_to_add [1]; \ + name_add_to [2] += name_to_add [2]; \ + name_add_to [1] += (name_add_to [0] >> 32u); \ + name_add_to [0] = (uint32_t) name_add_to [0]; \ + name_add_to [2] += (name_add_to [1] >> 32u); \ + name_add_to [1] = (uint32_t) name_add_to [1]; \ + \ + ECMA_NUMBER_CONVERSION_96BIT_INTEGER_CHECK_PARTS_ARE_32BIT (name_add_to); \ + ECMA_NUMBER_CONVERSION_96BIT_INTEGER_CHECK_PARTS_ARE_32BIT (name_to_add); \ +} + +/** + * Divide 96-bit integer by 10 + */ +#define ECMA_NUMBER_CONVERSION_96BIT_INTEGER_DIV_10(name) \ +{ \ + ECMA_NUMBER_CONVERSION_96BIT_INTEGER_CHECK_PARTS_ARE_32BIT (name); \ + \ + /* estimation of reciprocal of 10 */ \ + const uint64_t div10_p_low = 0x9999999aul; \ + const uint64_t div10_p_mid = 0x99999999ul; \ + const uint64_t div10_p_high = 0x19999999ul; \ + \ + uint64_t intermediate [6] = { 0, 0, 0, 0, 0, 0 }; \ + uint64_t tmp; \ + tmp = div10_p_low * name[0]; \ + intermediate [0] += (uint32_t) tmp; \ + intermediate [1] += tmp >> 32u; \ + tmp = div10_p_low * name[1]; \ + intermediate [1] += (uint32_t) tmp; \ + intermediate [2] += tmp >> 32u; \ + tmp = div10_p_mid * name[0]; \ + intermediate [1] += (uint32_t) tmp; \ + intermediate [2] += tmp >> 32u; \ + tmp = div10_p_low * name[2]; \ + intermediate [2] += (uint32_t) tmp; \ + intermediate [3] += tmp >> 32u; \ + tmp = div10_p_mid * name[1]; \ + intermediate [2] += (uint32_t) tmp; \ + intermediate [3] += tmp >> 32u; \ + tmp = div10_p_high * name[0]; \ + intermediate [2] += (uint32_t) tmp; \ + intermediate [3] += tmp >> 32u; \ + tmp = div10_p_mid * name[2]; \ + intermediate [3] += (uint32_t) tmp; \ + intermediate [4] += tmp >> 32u; \ + tmp = div10_p_high * name[1]; \ + intermediate [3] += (uint32_t) tmp; \ + intermediate [4] += tmp >> 32u; \ + tmp = div10_p_high * name[2]; \ + intermediate [4] += (uint32_t) tmp; \ + intermediate [5] += tmp >> 32u; \ + \ + intermediate[1] += intermediate[0] >> 32u; \ + intermediate[0] = (uint32_t) intermediate [0]; \ + intermediate[2] += intermediate[1] >> 32u; \ + intermediate[1] = (uint32_t) intermediate [1]; \ + intermediate[3] += intermediate[2] >> 32u; \ + intermediate[2] = (uint32_t) intermediate [2]; \ + intermediate[4] += intermediate[3] >> 32u; \ + intermediate[3] = (uint32_t) intermediate [3]; \ + intermediate[5] += intermediate[4] >> 32u; \ + intermediate[4] = (uint32_t) intermediate [4]; \ + \ + name[0] = intermediate [3]; \ + name[1] = intermediate [4]; \ + name[2] = intermediate [5]; \ + \ + ECMA_NUMBER_CONVERSION_96BIT_INTEGER_CHECK_PARTS_ARE_32BIT (name); \ +} + +/** + * @} + */ + /** * ECMA-defined conversion of string (zero-terminated) to Number. * @@ -38,7 +222,7 @@ ecma_number_t ecma_zt_string_to_number (const ecma_char_t *str_p) /**< zero-terminated string */ { - TODO (Check conversion precision); + TODO (Check license issues); const ecma_char_t dec_digits_range[10] = { '0', '9' }; const ecma_char_t hex_lower_digits_range[10] = { 'a', 'f' }; @@ -52,6 +236,7 @@ ecma_zt_string_to_number (const ecma_char_t *str_p) /**< zero-terminated string const ecma_char_t *begin_p = str_p; const ecma_char_t *end_p = begin_p; + while (*end_p != ECMA_CHAR_NULL) { end_p++; @@ -79,26 +264,16 @@ ecma_zt_string_to_number (const ecma_char_t *str_p) /**< zero-terminated string const ssize_t literal_len = end_p - begin_p + 1; - bool is_hex_literal = false; - if (literal_len > 2 - && *begin_p == dec_digits_range[0]) + && begin_p[0] == dec_digits_range[0] + && (begin_p[1] == hex_x_chars[0] + || begin_p[1] == hex_x_chars[1])) { - begin_p++; + /* Hex literal handling */ + begin_p += 2; - if (*begin_p == hex_x_chars[0] - || *begin_p == hex_x_chars[1]) - { - is_hex_literal = true; + ecma_number_t num = 0; - begin_p++; - } - } - - ecma_number_t num = 0; - - if (is_hex_literal) - { for (const ecma_char_t* iter_p = begin_p; iter_p <= end_p; iter_p++) @@ -149,6 +324,7 @@ ecma_zt_string_to_number (const ecma_char_t *str_p) /**< zero-terminated string return ecma_number_make_nan (); } + /* Checking if significant part of parse string is equal to "Infinity" */ const ecma_char_t *infinity_zt_str_p = ecma_get_magic_string_zt (ECMA_MAGIC_STRING_INFINITY_UL); for (const ecma_char_t *iter_p = begin_p, *iter_infinity_p = infinity_zt_str_p; @@ -166,6 +342,11 @@ ecma_zt_string_to_number (const ecma_char_t *str_p) /**< zero-terminated string } } + uint64_t fraction_uint64 = 0; + uint32_t digits = 0; + int32_t e = 0; + + /* Parsing digits before dot (or before end of digits part if there is no dot in number) */ while (begin_p <= end_p) { int32_t digit_value; @@ -180,41 +361,30 @@ ecma_zt_string_to_number (const ecma_char_t *str_p) /**< zero-terminated string break; } - num = num * 10 + (ecma_number_t) digit_value; + if (digits != 0 || digit_value != 0) + { + if (digits < ECMA_NUMBER_MAX_DIGITS) + { + fraction_uint64 = fraction_uint64 * 10 + (uint32_t) digit_value; + digits++; + } + else if (e <= 100000) /* Some limit to not overflow exponent value + (so big exponent anyway will make number + rounded to infinity) */ + { + e++; + } + } begin_p++; } - if (begin_p > end_p) - { - if (sign) - { - return -num; - } - else - { - return num; - } - } - - int32_t e = 0; - - if (*begin_p == dot_char) + if (begin_p <= end_p + && *begin_p == dot_char) { begin_p++; - if (begin_p > end_p) - { - if (sign) - { - return -num; - } - else - { - return num; - } - } - + /* Parsing number's part that is placed after dot */ while (begin_p <= end_p) { int32_t digit_value; @@ -229,23 +399,28 @@ ecma_zt_string_to_number (const ecma_char_t *str_p) /**< zero-terminated string break; } - num = num * 10 + (ecma_number_t) digit_value; - e--; + if (digits < ECMA_NUMBER_MAX_DIGITS) + { + if (digits != 0 || digit_value != 0) + { + fraction_uint64 = fraction_uint64 * 10 + (uint32_t) digit_value; + digits++; + } + + e--; + } begin_p++; } } - if (sign) - { - num = -num; - } - - int e_in_lit = 0; + /* Parsing exponent literal */ + int32_t e_in_lit = 0; bool e_in_lit_sign = false; - if (*begin_p == e_chars[0] - || *begin_p == e_chars[1]) + if (begin_p <= end_p + && (*begin_p == e_chars[0] + || *begin_p == e_chars[1])) { begin_p++; @@ -275,64 +450,182 @@ ecma_zt_string_to_number (const ecma_char_t *str_p) /**< zero-terminated string } else { - break; + return ecma_number_make_nan (); } e_in_lit = e_in_lit * 10 + digit_value; - if (e_in_lit > 10000) - { - if (e_in_lit_sign) - { - return 0; - } - else - { - return ecma_number_make_infinity (sign); - } - } - begin_p++; } } + /* Adding value of exponent literal to exponent value */ if (e_in_lit_sign) { - e_in_lit -= e; + e -= e_in_lit; } else { - e_in_lit += e; + e += e_in_lit; } - if (e_in_lit < 0) + bool e_sign; + + if (e < 0) { - JERRY_ASSERT (!e_in_lit_sign); - e_in_lit_sign = true; - e_in_lit = -e_in_lit; - } - - ecma_number_t m = e_in_lit_sign ? (ecma_number_t) 0.1 : (ecma_number_t) 10.0; - - while (e_in_lit) - { - if (e_in_lit % 2) - { - num *= m; - } - - m *= m; - e_in_lit /= 2; - } - - if (begin_p > end_p) - { - return num; + e_sign = true; + e = -e; } else + { + e_sign = false; + } + + if (begin_p <= end_p) { return ecma_number_make_nan (); } + + JERRY_ASSERT (begin_p == end_p + 1); + + if (fraction_uint64 == 0) + { + return ECMA_NUMBER_ZERO; + } + + int32_t binary_exponent = 1; + + /* + * 96-bit mantissa storage + * + * Normalized: |4 bits zero|92-bit mantissa with highest bit set to 1 if mantissa is non-zero| + */ + ECMA_NUMBER_CONVERSION_96BIT_INTEGER (fraction_uint96); + ECMA_NUMBER_CONVERSION_96BIT_INTEGER_INIT (fraction_uint96, + fraction_uint64 >> 32u, + (uint32_t) fraction_uint64, + 0ull); + + /* Normalizing mantissa */ + JERRY_ASSERT (ECMA_NUMBER_CONVERSION_96BIT_INTEGER_IS_BIT_MASK_ZERO (fraction_uint96, 92)); + + while (ECMA_NUMBER_CONVERSION_96BIT_INTEGER_IS_BIT_MASK_ZERO (fraction_uint96, 91)) + { + ECMA_NUMBER_CONVERSION_96BIT_INTEGER_LEFT_SHIFT (fraction_uint96); + binary_exponent--; + + JERRY_ASSERT (!ECMA_NUMBER_CONVERSION_96BIT_INTEGER_IS_ZERO (fraction_uint96)); + } + + if (!e_sign) + { + /* positive or zero decimal exponent */ + JERRY_ASSERT (e >= 0); + + while (e > 0) + { + JERRY_ASSERT (ECMA_NUMBER_CONVERSION_96BIT_INTEGER_IS_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); + + e--; + + /* Normalizing mantissa */ + while (!ECMA_NUMBER_CONVERSION_96BIT_INTEGER_IS_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)) + { + ECMA_NUMBER_CONVERSION_96BIT_INTEGER_LEFT_SHIFT (fraction_uint96); + + binary_exponent--; + + JERRY_ASSERT (!ECMA_NUMBER_CONVERSION_96BIT_INTEGER_IS_ZERO (fraction_uint96)); + } + } + } + else + { + /* negative decimal exponent */ + JERRY_ASSERT (e != 0); + + while (e > 0) + { + /* Denormalizing mantissa, moving highest 1 to 95-bit */ + while (ECMA_NUMBER_CONVERSION_96BIT_INTEGER_IS_BIT_MASK_ZERO (fraction_uint96, 95)) + { + ECMA_NUMBER_CONVERSION_96BIT_INTEGER_LEFT_SHIFT (fraction_uint96); + + binary_exponent--; + + JERRY_ASSERT (!ECMA_NUMBER_CONVERSION_96BIT_INTEGER_IS_ZERO (fraction_uint96)); + } + + ECMA_NUMBER_CONVERSION_96BIT_INTEGER_DIV_10 (fraction_uint96); + + e--; + } + + /* Normalizing mantissa */ + while (!ECMA_NUMBER_CONVERSION_96BIT_INTEGER_IS_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)) + { + ECMA_NUMBER_CONVERSION_96BIT_INTEGER_LEFT_SHIFT (fraction_uint96); + + binary_exponent--; + + JERRY_ASSERT (!ECMA_NUMBER_CONVERSION_96BIT_INTEGER_IS_ZERO (fraction_uint96)); + } + } + + 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)); + + /* + * 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)) + { + ECMA_NUMBER_CONVERSION_96BIT_INTEGER_RIGHT_SHIFT (fraction_uint96); + + binary_exponent++; + } + while (ECMA_NUMBER_CONVERSION_96BIT_INTEGER_IS_BIT_MASK_ZERO (fraction_uint96, 84)) + { + ECMA_NUMBER_CONVERSION_96BIT_INTEGER_LEFT_SHIFT (fraction_uint96); + + binary_exponent--; + + 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)); + + ECMA_NUMBER_CONVERSION_96BIT_INTEGER_ROUND_HIGH_AND_MIDDLE_TO_UINT64 (fraction_uint96, fraction_uint64); + + return ecma_number_make_from_sign_mantissa_and_exponent (sign, + fraction_uint64, + binary_exponent); } /* ecma_zt_string_to_number */ /** diff --git a/src/libecmaobjects/ecma-helpers-number.c b/src/libecmaobjects/ecma-helpers-number.c index ba70cd665..efd78d8bd 100644 --- a/src/libecmaobjects/ecma-helpers-number.c +++ b/src/libecmaobjects/ecma-helpers-number.c @@ -352,8 +352,8 @@ ecma_number_get_fraction_and_exponent (ecma_number_t num, /**< ecma-number */ exponent = (int32_t) biased_exp - ecma_number_exponent_bias; JERRY_ASSERT (biased_exp > 0 && biased_exp < (1u << ECMA_NUMBER_BIASED_EXP_WIDTH) - 1); - JERRY_ASSERT ((fraction & (1ul << ECMA_NUMBER_FRACTION_WIDTH)) == 0); - fraction |= 1ul << ECMA_NUMBER_FRACTION_WIDTH; + JERRY_ASSERT ((fraction & (1ull << ECMA_NUMBER_FRACTION_WIDTH)) == 0); + fraction |= 1ull << ECMA_NUMBER_FRACTION_WIDTH; } *out_fraction_p = fraction; @@ -378,14 +378,109 @@ ecma_number_make_normal_positive_from_fraction_and_exponent (uint64_t fraction, uint32_t biased_exp = (uint32_t) (exponent + ecma_number_exponent_bias); JERRY_ASSERT (biased_exp > 0 && biased_exp < (1u << ECMA_NUMBER_BIASED_EXP_WIDTH) - 1); + JERRY_ASSERT ((fraction & ~((1ull << (ECMA_NUMBER_FRACTION_WIDTH + 1)) - 1)) == 0); + JERRY_ASSERT ((fraction & (1ull << ECMA_NUMBER_FRACTION_WIDTH)) != 0); u.fields.biased_exp = biased_exp & ((1u << ECMA_NUMBER_BIASED_EXP_WIDTH) - 1); - u.fields.fraction = fraction & ((1ul << ECMA_NUMBER_FRACTION_WIDTH) - 1); + u.fields.fraction = fraction & ((1ull << ECMA_NUMBER_FRACTION_WIDTH) - 1); u.fields.sign = 0; return u.value; } /* ecma_number_make_normal_positive_from_fraction_and_exponent */ +/** + * Make Number of given sign from given mantissa value and binary exponent + * + * @return ecma-number (possibly Infinity of specified sign) + */ +ecma_number_t +ecma_number_make_from_sign_mantissa_and_exponent (bool sign, /**< true - for negative sign, + false - for positive sign */ + uint64_t mantissa, /**< mantissa */ + int32_t exponent) /**< binary exponent */ +{ + union + { + ecma_number_fields_t fields; + ecma_number_t value; + } u; + + /* Rounding mantissa to fit into fraction field width */ + if (mantissa & ~((1ull << (ECMA_NUMBER_FRACTION_WIDTH + 1)) - 1)) + { + /* Rounded mantissa looks like the following: |00...0|1|fraction_width mantissa bits| */ + while ((mantissa & ~((1ull << (ECMA_NUMBER_FRACTION_WIDTH + 1)) - 1)) != 0) + { + uint64_t rightmost_bit = (mantissa & 1); + + exponent++; + mantissa >>= 1; + + if ((mantissa & ~((1ull << (ECMA_NUMBER_FRACTION_WIDTH + 1)) - 1)) == 0) + { + /* Rounding to nearest value */ + mantissa += rightmost_bit; + + /* In the first case loop is finished, + and in the second - just one shift follows and then loop finishes */ + JERRY_ASSERT (((mantissa & ~((1ull << (ECMA_NUMBER_FRACTION_WIDTH + 1)) - 1)) == 0) + || (mantissa == (1ull << (ECMA_NUMBER_FRACTION_WIDTH + 1)))); + } + } + } + + /* Normalizing mantissa */ + while (mantissa != 0 + && ((mantissa & (1ull << ECMA_NUMBER_FRACTION_WIDTH)) == 0)) + { + exponent--; + mantissa <<= 1; + } + + /* Moving floating point */ + exponent += ECMA_NUMBER_FRACTION_WIDTH - 1; + + int32_t biased_exp_signed = exponent + ecma_number_exponent_bias; + + if (biased_exp_signed < 1) + { + /* Denormalizing mantissa if biased_exponent is less than zero */ + while (biased_exp_signed < 0) + { + biased_exp_signed++; + mantissa >>= 1; + } + + /* Rounding to nearest value */ + mantissa += 1; + mantissa >>= 1; + + /* Encoding denormalized exponent */ + biased_exp_signed = 0; + } + else + { + /* Clearing highest mantissa bit that should have been non-zero if mantissa is non-zero */ + mantissa &= ~(1ull << ECMA_NUMBER_FRACTION_WIDTH); + } + + uint32_t biased_exp = (uint32_t) biased_exp_signed; + + if (biased_exp >= ((1u << ECMA_NUMBER_BIASED_EXP_WIDTH) - 1)) + { + return ecma_number_make_infinity (sign); + } + + JERRY_ASSERT (biased_exp < (1u << ECMA_NUMBER_BIASED_EXP_WIDTH) - 1); + JERRY_ASSERT ((mantissa & ~((1ull << ECMA_NUMBER_FRACTION_WIDTH) - 1)) == 0); + + u.fields.biased_exp = biased_exp & ((1u << ECMA_NUMBER_BIASED_EXP_WIDTH) - 1); + u.fields.fraction = mantissa & ((1ull << ECMA_NUMBER_FRACTION_WIDTH) - 1); + u.fields.sign = (sign ? 1 : 0); + + return u.value; +} /* ecma_number_make_from_sign_mantissa_and_exponent */ + /** * Negate ecma-number * diff --git a/src/libecmaobjects/ecma-helpers.h b/src/libecmaobjects/ecma-helpers.h index 6e95f8e99..48a3a09ea 100644 --- a/src/libecmaobjects/ecma-helpers.h +++ b/src/libecmaobjects/ecma-helpers.h @@ -144,6 +144,10 @@ ecma_number_get_fraction_and_exponent (ecma_number_t num, extern ecma_number_t ecma_number_make_normal_positive_from_fraction_and_exponent (uint64_t fraction, int32_t exponent); +extern ecma_number_t +ecma_number_make_from_sign_mantissa_and_exponent (bool sign, + uint64_t mantissa, + int32_t exponent); extern ecma_number_t ecma_number_negate (ecma_number_t num); extern ecma_number_t ecma_number_trunc (ecma_number_t num); extern ecma_number_t ecma_number_add (ecma_number_t left_num, ecma_number_t right_num); diff --git a/tests/jerry/math_log.js b/tests/jerry/math_log.js index 362fd42ed..9a048301a 100644 --- a/tests/jerry/math_log.js +++ b/tests/jerry/math_log.js @@ -31,7 +31,7 @@ var very_close_to_1_but_less = 0.999999; assert( very_close_to_1_but_less < 1.0 ); assert( Math.log (very_close_to_1_but_less) <= 0.0 ); -assert( Math.log (very_close_to_1_but_less) >= -0.000001 ); +assert( Math.log (very_close_to_1_but_less) >= -0.00001 ); assert( Math.log (2.7182818284590452354) >= 0.999999 ); assert( Math.log (2.7182818284590452354) <= 1.000001 );