mirror of
https://github.com/jerryscript-project/jerryscript.git
synced 2025-12-15 16:29:21 +00:00
Improve float number handling and conversion (#4820)
Fixes #4739. JerryScript-DCO-1.0-Signed-off-by: Dániel Bátyai dbatyai@inf.u-szeged.hu
This commit is contained in:
parent
a1c1d42710
commit
81d2319144
@ -283,7 +283,6 @@ set(SOURCE_CORE_FILES
|
||||
ecma/operations/ecma-iterator-object.c
|
||||
ecma/operations/ecma-jobqueue.c
|
||||
ecma/operations/ecma-lex-env.c
|
||||
ecma/operations/ecma-number-arithmetic.c
|
||||
ecma/operations/ecma-number-object.c
|
||||
ecma/operations/ecma-objects-general.c
|
||||
ecma/operations/ecma-objects.c
|
||||
@ -462,7 +461,6 @@ if(ENABLE_AMALGAM)
|
||||
ecma/operations/ecma-iterator-object.h
|
||||
ecma/operations/ecma-jobqueue.h
|
||||
ecma/operations/ecma-lex-env.h
|
||||
ecma/operations/ecma-number-arithmetic.h
|
||||
ecma/operations/ecma-number-object.h
|
||||
ecma/operations/ecma-objects-general.h
|
||||
ecma/operations/ecma-objects.h
|
||||
|
||||
@ -1386,112 +1386,34 @@ typedef struct
|
||||
#define ECMA_PROPERTY_FLAGS_MASK \
|
||||
((uint16_t) (JERRY_PROP_IS_CONFIGURABLE | JERRY_PROP_IS_ENUMERABLE | JERRY_PROP_IS_WRITABLE))
|
||||
|
||||
#if !JERRY_NUMBER_TYPE_FLOAT64
|
||||
/**
|
||||
* Description of an ecma-number
|
||||
*/
|
||||
typedef float ecma_number_t;
|
||||
|
||||
/**
|
||||
* It makes possible to read/write an ecma_number_t as uint32_t without strict aliasing rule violation.
|
||||
*/
|
||||
typedef union
|
||||
{
|
||||
ecma_number_t as_ecma_number_t;
|
||||
uint32_t as_uint32_t;
|
||||
} ecma_number_accessor_t;
|
||||
|
||||
#define DOUBLE_TO_ECMA_NUMBER_T(value) (ecma_number_t) (value)
|
||||
|
||||
/**
|
||||
* Maximum number of significant digits that ecma-number can store
|
||||
*/
|
||||
#define ECMA_NUMBER_MAX_DIGITS (9)
|
||||
|
||||
/**
|
||||
* Width of sign field
|
||||
*
|
||||
* See also:
|
||||
* IEEE-754 2008, 3.6, Table 3.5
|
||||
*/
|
||||
#define ECMA_NUMBER_SIGN_WIDTH (1)
|
||||
|
||||
/**
|
||||
* Width of biased exponent field
|
||||
*
|
||||
* See also:
|
||||
* IEEE-754 2008, 3.6, Table 3.5
|
||||
*/
|
||||
#define ECMA_NUMBER_BIASED_EXP_WIDTH (8)
|
||||
|
||||
/**
|
||||
* Width of fraction field
|
||||
*
|
||||
* See also:
|
||||
* IEEE-754 2008, 3.6, Table 3.5
|
||||
*/
|
||||
#define ECMA_NUMBER_FRACTION_WIDTH (23)
|
||||
#elif JERRY_NUMBER_TYPE_FLOAT64
|
||||
/**
|
||||
* Description of an ecma-number
|
||||
*/
|
||||
#if JERRY_NUMBER_TYPE_FLOAT64
|
||||
typedef double ecma_number_t;
|
||||
|
||||
/**
|
||||
* It makes possible to read/write an ecma_number_t as uint64_t without strict aliasing rule violation.
|
||||
*/
|
||||
typedef union
|
||||
{
|
||||
ecma_number_t as_ecma_number_t;
|
||||
uint64_t as_uint64_t;
|
||||
} ecma_number_accessor_t;
|
||||
|
||||
#define DOUBLE_TO_ECMA_NUMBER_T(value) value
|
||||
|
||||
/**
|
||||
* Maximum number of significant digits that ecma-number can store
|
||||
*/
|
||||
#define ECMA_NUMBER_MAX_DIGITS (19)
|
||||
|
||||
/**
|
||||
* Width of sign field
|
||||
*
|
||||
* See also:
|
||||
* IEEE-754 2008, 3.6, Table 3.5
|
||||
*/
|
||||
#define ECMA_NUMBER_SIGN_WIDTH (1)
|
||||
|
||||
/**
|
||||
* Width of biased exponent field
|
||||
*
|
||||
* See also:
|
||||
* IEEE-754 2008, 3.6, Table 3.5
|
||||
*/
|
||||
#define ECMA_NUMBER_BIASED_EXP_WIDTH (11)
|
||||
|
||||
/**
|
||||
* Width of fraction field
|
||||
*
|
||||
* See also:
|
||||
* IEEE-754 2008, 3.6, Table 3.5
|
||||
*/
|
||||
#define ECMA_NUMBER_FRACTION_WIDTH (52)
|
||||
#else /* !JERRY_NUMBER_TYPE_FLOAT64 */
|
||||
typedef float ecma_number_t;
|
||||
#endif /* !JERRY_NUMBER_TYPE_FLOAT64 */
|
||||
|
||||
/**
|
||||
* Convert double to an ecma-number.
|
||||
*/
|
||||
#define DOUBLE_TO_ECMA_NUMBER_T(value) ((ecma_number_t) (value))
|
||||
|
||||
/**
|
||||
* Value '0' of ecma_number_t
|
||||
*/
|
||||
#define ECMA_NUMBER_ZERO ((ecma_number_t) 0)
|
||||
#define ECMA_NUMBER_ZERO ((ecma_number_t) 0.0f)
|
||||
|
||||
/**
|
||||
* Value '1' of ecma_number_t
|
||||
*/
|
||||
#define ECMA_NUMBER_ONE ((ecma_number_t) 1)
|
||||
#define ECMA_NUMBER_ONE ((ecma_number_t) 1.0f)
|
||||
|
||||
/**
|
||||
* Value '2' of ecma_number_t
|
||||
*/
|
||||
#define ECMA_NUMBER_TWO ((ecma_number_t) 2)
|
||||
#define ECMA_NUMBER_TWO ((ecma_number_t) 2.0f)
|
||||
|
||||
/**
|
||||
* Value '0.5' of ecma_number_t
|
||||
@ -1501,117 +1423,7 @@ typedef union
|
||||
/**
|
||||
* Value '-1' of ecma_number_t
|
||||
*/
|
||||
#define ECMA_NUMBER_MINUS_ONE ((ecma_number_t) -1)
|
||||
|
||||
#if !JERRY_NUMBER_TYPE_FLOAT64
|
||||
/**
|
||||
* Number.MIN_VALUE (i.e., the smallest positive value of ecma-number)
|
||||
*
|
||||
* See also: ECMA_262 v5, 15.7.3.3
|
||||
*/
|
||||
#define ECMA_NUMBER_MIN_VALUE (FLT_MIN)
|
||||
/**
|
||||
* Number.MAX_VALUE (i.e., the maximum value of ecma-number)
|
||||
*
|
||||
* See also: ECMA_262 v5, 15.7.3.2
|
||||
*/
|
||||
#define ECMA_NUMBER_MAX_VALUE (FLT_MAX)
|
||||
/**
|
||||
* Number.EPSILON
|
||||
*
|
||||
* See also: ECMA_262 v6, 20.1.2.1
|
||||
*/
|
||||
#define ECMA_NUMBER_EPSILON ((ecma_number_t) 1.1920928955078125e-7)
|
||||
|
||||
/**
|
||||
* Number.MAX_SAFE_INTEGER
|
||||
*
|
||||
* See also: ECMA_262 v6, 20.1.2.6
|
||||
*/
|
||||
#define ECMA_NUMBER_MAX_SAFE_INTEGER ((ecma_number_t) 0xFFFFFF)
|
||||
|
||||
/**
|
||||
* Number.MIN_SAFE_INTEGER
|
||||
*
|
||||
* See also: ECMA_262 v6, 20.1.2.8
|
||||
*/
|
||||
#define ECMA_NUMBER_MIN_SAFE_INTEGER ((ecma_number_t) -0xFFFFFF)
|
||||
#elif JERRY_NUMBER_TYPE_FLOAT64
|
||||
/**
|
||||
* Number.MAX_VALUE (i.e., the maximum value of ecma-number)
|
||||
*
|
||||
* See also: ECMA_262 v5, 15.7.3.2
|
||||
*/
|
||||
#define ECMA_NUMBER_MAX_VALUE ((ecma_number_t) 1.7976931348623157e+308)
|
||||
|
||||
/**
|
||||
* Number.MIN_VALUE (i.e., the smallest positive value of ecma-number)
|
||||
*
|
||||
* See also: ECMA_262 v5, 15.7.3.3
|
||||
*/
|
||||
#define ECMA_NUMBER_MIN_VALUE ((ecma_number_t) 5e-324)
|
||||
|
||||
/**
|
||||
* Number.EPSILON
|
||||
*
|
||||
* See also: ECMA_262 v6, 20.1.2.1
|
||||
*/
|
||||
#define ECMA_NUMBER_EPSILON ((ecma_number_t) 2.2204460492503130808472633361816e-16)
|
||||
|
||||
/**
|
||||
* Number.MAX_SAFE_INTEGER
|
||||
*
|
||||
* See also: ECMA_262 v6, 20.1.2.6
|
||||
*/
|
||||
#define ECMA_NUMBER_MAX_SAFE_INTEGER ((ecma_number_t) 0x1FFFFFFFFFFFFF)
|
||||
|
||||
/**
|
||||
* Number.MIN_SAFE_INTEGER
|
||||
*
|
||||
* See also: ECMA_262 v6, 20.1.2.8
|
||||
*/
|
||||
#define ECMA_NUMBER_MIN_SAFE_INTEGER ((ecma_number_t) -0x1FFFFFFFFFFFFF)
|
||||
#endif /* !JERRY_NUMBER_TYPE_FLOAT64 */
|
||||
|
||||
/**
|
||||
* Euler number
|
||||
*/
|
||||
#define ECMA_NUMBER_E ((ecma_number_t) 2.7182818284590452354)
|
||||
|
||||
/**
|
||||
* Natural logarithm of 10
|
||||
*/
|
||||
#define ECMA_NUMBER_LN10 ((ecma_number_t) 2.302585092994046)
|
||||
|
||||
/**
|
||||
* Natural logarithm of 2
|
||||
*/
|
||||
#define ECMA_NUMBER_LN2 ((ecma_number_t) 0.6931471805599453)
|
||||
|
||||
/**
|
||||
* Logarithm base 2 of the Euler number
|
||||
*/
|
||||
#define ECMA_NUMBER_LOG2E ((ecma_number_t) 1.4426950408889634)
|
||||
|
||||
/**
|
||||
* Logarithm base 10 of the Euler number
|
||||
*/
|
||||
#define ECMA_NUMBER_LOG10E ((ecma_number_t) 0.4342944819032518)
|
||||
|
||||
/**
|
||||
* Pi number
|
||||
*/
|
||||
#define ECMA_NUMBER_PI ((ecma_number_t) 3.1415926535897932)
|
||||
|
||||
/**
|
||||
* Square root of 0.5
|
||||
*/
|
||||
#define ECMA_NUMBER_SQRT_1_2 ((ecma_number_t) 0.7071067811865476)
|
||||
|
||||
/**
|
||||
* Square root of 2
|
||||
*/
|
||||
#define ECMA_NUMBER_SQRT2 ((ecma_number_t) 1.4142135623730951)
|
||||
#define ECMA_NUMBER_MINUS_ONE ((ecma_number_t) -1.0f)
|
||||
|
||||
/**
|
||||
* Maximum number of characters in string representation of ecma-number
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
#include <math.h>
|
||||
|
||||
#include "ecma-globals.h"
|
||||
#include "ecma-helpers-number.h"
|
||||
#include "ecma-helpers.h"
|
||||
|
||||
#include "jrt-libc-includes.h"
|
||||
@ -41,8 +42,8 @@
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint64_t lo; /**< low 64 bits */
|
||||
uint64_t hi; /**< high 64 bits */
|
||||
uint64_t lo; /**< low 64 bits */
|
||||
} ecma_uint128_t;
|
||||
|
||||
/**
|
||||
@ -60,58 +61,58 @@ ecma_round_high_to_uint64 (ecma_uint128_t *num_p)
|
||||
{
|
||||
return (num_p->hi + 1);
|
||||
}
|
||||
|
||||
return num_p->hi;
|
||||
} /* ecma_round_high_to_uint64 */
|
||||
|
||||
/**
|
||||
* Check if 128-bit integer is zero
|
||||
* Left shift 128-bit integer by max 63 bits.
|
||||
*/
|
||||
#define ECMA_UINT128_IS_ZERO(name) (name.hi == 0 && name.lo == 0)
|
||||
static void JERRY_ATTR_ALWAYS_INLINE
|
||||
ecma_uint128_shift_left (ecma_uint128_t *num_p, int32_t shift)
|
||||
{
|
||||
num_p->hi = (num_p->hi << shift) | (num_p->lo >> (64 - shift));
|
||||
num_p->lo <<= shift;
|
||||
} /* ecma_uint128_shift_left */
|
||||
|
||||
/**
|
||||
* Left shift 128-bit integer by max 63 bits
|
||||
* Right shift 128-bit integer by max 63 bits.
|
||||
*/
|
||||
#define ECMA_UINT128_LEFT_SHIFT_MAX63(name, shift) \
|
||||
{ \
|
||||
name.hi = (name.hi << (shift)) | (name.lo >> (64 - (shift))); \
|
||||
name.lo <<= (shift); \
|
||||
}
|
||||
static void JERRY_ATTR_ALWAYS_INLINE
|
||||
ecma_uint128_shift_right (ecma_uint128_t *num_p, int32_t shift)
|
||||
{
|
||||
num_p->lo = (num_p->lo >> shift) | (num_p->hi << (64 - shift));
|
||||
num_p->hi >>= shift;
|
||||
} /* ecma_uint128_shift_right */
|
||||
|
||||
/**
|
||||
* Right shift 128-bit integer by max 63 bits
|
||||
* Add two 128-bit integer values and assign the result to the left one.
|
||||
*/
|
||||
#define ECMA_UINT128_RIGHT_SHIFT_MAX63(name, shift) \
|
||||
{ \
|
||||
name.lo = (name.lo >> (shift)) | (name.hi << (64 - (shift))); \
|
||||
name.hi >>= (shift); \
|
||||
}
|
||||
static void
|
||||
ecma_uint128_add (ecma_uint128_t *left_p, ecma_uint128_t *right_p)
|
||||
{
|
||||
left_p->hi += right_p->hi;
|
||||
left_p->lo += right_p->lo;
|
||||
|
||||
/**
|
||||
* Add 128-bit integer
|
||||
*/
|
||||
#define ECMA_UINT128_ADD(name_add_to, name_to_add) \
|
||||
{ \
|
||||
name_add_to.hi += name_to_add.hi; \
|
||||
name_add_to.lo += name_to_add.lo; \
|
||||
if (name_add_to.lo < name_to_add.lo) \
|
||||
{ \
|
||||
name_add_to.hi++; \
|
||||
} \
|
||||
if (left_p->lo < right_p->lo)
|
||||
{
|
||||
left_p->hi++;
|
||||
}
|
||||
} /* ecma_uint128_add */
|
||||
|
||||
/**
|
||||
* Multiply 128-bit integer by 10
|
||||
*/
|
||||
#define ECMA_UINT128_MUL10(name) \
|
||||
{ \
|
||||
ECMA_UINT128_LEFT_SHIFT_MAX63 (name, 1u); \
|
||||
\
|
||||
ecma_uint128_t name##_tmp = name; \
|
||||
\
|
||||
ECMA_UINT128_LEFT_SHIFT_MAX63 (name##_tmp, 2u); \
|
||||
\
|
||||
ECMA_UINT128_ADD (name, name##_tmp); \
|
||||
}
|
||||
static void
|
||||
ecma_uint128_mul10 (ecma_uint128_t *num_p)
|
||||
{
|
||||
ecma_uint128_shift_left (num_p, 1u);
|
||||
|
||||
ecma_uint128_t tmp = { .hi = num_p->hi, .lo = num_p->lo };
|
||||
ecma_uint128_shift_left (&tmp, 2u);
|
||||
|
||||
ecma_uint128_add (num_p, &tmp);
|
||||
} /* ecma_uint128_mul10 */
|
||||
|
||||
/**
|
||||
* Divide 128-bit integer by 10
|
||||
@ -128,121 +129,122 @@ ecma_round_high_to_uint64 (ecma_uint128_t *num_p)
|
||||
*
|
||||
* Q = Q3 *2^96 + Q2 *2^64 + Q1 *2^32 + Q0 *2^0 // 128-bit quotient
|
||||
*/
|
||||
#define ECMA_UINT128_DIV10(name) \
|
||||
{ \
|
||||
/* estimation of reciprocal of 10, 128 bits right of the binary point (T1 == T2) */ \
|
||||
const uint64_t tenth_l = 0x9999999aul; \
|
||||
const uint64_t tenth_m = 0x99999999ul; \
|
||||
const uint64_t tenth_h = 0x19999999ul; \
|
||||
\
|
||||
uint64_t l0 = ((uint32_t) name.lo) * tenth_l; \
|
||||
uint64_t l1 = (name.lo >> 32u) * tenth_l; \
|
||||
uint64_t l2 = ((uint32_t) name.hi) * tenth_l; \
|
||||
uint64_t l3 = (name.hi >> 32u) * tenth_l; \
|
||||
uint64_t m0 = ((uint32_t) name.lo) * tenth_m; \
|
||||
uint64_t m1 = (name.lo >> 32u) * tenth_m; \
|
||||
uint64_t m2 = ((uint32_t) name.hi) * tenth_m; \
|
||||
uint64_t m3 = (name.hi >> 32u) * tenth_m; \
|
||||
uint64_t h0 = ((uint32_t) name.lo) * tenth_h; \
|
||||
uint64_t h1 = (name.lo >> 32u) * tenth_h; \
|
||||
uint64_t h2 = ((uint32_t) name.hi) * tenth_h; \
|
||||
uint64_t h3 = (name.hi >> 32u) * tenth_h; \
|
||||
\
|
||||
uint64_t q0 = l0 >> 32u; \
|
||||
q0 += (uint32_t) l1; \
|
||||
q0 += (uint32_t) m0; \
|
||||
\
|
||||
q0 >>= 32u; \
|
||||
q0 += l1 >> 32u; \
|
||||
q0 += m0 >> 32u; \
|
||||
q0 += (uint32_t) l2; \
|
||||
q0 += (uint32_t) m1; \
|
||||
q0 += (uint32_t) m0; \
|
||||
\
|
||||
q0 >>= 32u; \
|
||||
q0 += l2 >> 32u; \
|
||||
q0 += m1 >> 32u; \
|
||||
q0 += m0 >> 32u; \
|
||||
q0 += (uint32_t) l3; \
|
||||
q0 += (uint32_t) m2; \
|
||||
q0 += (uint32_t) m1; \
|
||||
q0 += (uint32_t) h0; \
|
||||
\
|
||||
q0 >>= 32u; \
|
||||
q0 += l3 >> 32u; \
|
||||
q0 += m2 >> 32u; \
|
||||
q0 += m1 >> 32u; \
|
||||
q0 += h0 >> 32u; \
|
||||
q0 += (uint32_t) m3; \
|
||||
q0 += (uint32_t) m2; \
|
||||
q0 += (uint32_t) h1; \
|
||||
\
|
||||
uint64_t q1 = q0 >> 32u; \
|
||||
q1 += m3 >> 32u; \
|
||||
q1 += m2 >> 32u; \
|
||||
q1 += h1 >> 32u; \
|
||||
q1 += (uint32_t) m3; \
|
||||
q1 += (uint32_t) h2; \
|
||||
\
|
||||
uint64_t q32 = q1 >> 32u; \
|
||||
q32 += m3 >> 32u; \
|
||||
q32 += h2 >> 32u; \
|
||||
q32 += h3; \
|
||||
\
|
||||
name.lo = (q1 << 32u) | ((uint32_t) q0); \
|
||||
name.hi = q32; \
|
||||
}
|
||||
static void
|
||||
ecma_uint128_div10 (ecma_uint128_t *num_p)
|
||||
{
|
||||
/* estimation of reciprocal of 10, 128 bits right of the binary point (T1 == T2) */
|
||||
const uint64_t tenth_l = 0x9999999aul;
|
||||
const uint64_t tenth_m = 0x99999999ul;
|
||||
const uint64_t tenth_h = 0x19999999ul;
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
const uint64_t l0 = ((uint32_t) num_p->lo) * tenth_l;
|
||||
const uint64_t l1 = (num_p->lo >> 32u) * tenth_l;
|
||||
const uint64_t l2 = ((uint32_t) num_p->hi) * tenth_l;
|
||||
const uint64_t l3 = (num_p->hi >> 32u) * tenth_l;
|
||||
const uint64_t m0 = ((uint32_t) num_p->lo) * tenth_m;
|
||||
const uint64_t m1 = (num_p->lo >> 32u) * tenth_m;
|
||||
const uint64_t m2 = ((uint32_t) num_p->hi) * tenth_m;
|
||||
const uint64_t m3 = (num_p->hi >> 32u) * tenth_m;
|
||||
const uint64_t h0 = ((uint32_t) num_p->lo) * tenth_h;
|
||||
const uint64_t h1 = (num_p->lo >> 32u) * tenth_h;
|
||||
const uint64_t h2 = ((uint32_t) num_p->hi) * tenth_h;
|
||||
const uint64_t h3 = (num_p->hi >> 32u) * tenth_h;
|
||||
|
||||
/**
|
||||
* Count leading zeros in the topmost 64 bits of a 128-bit integer.
|
||||
*/
|
||||
#define ECMA_UINT128_CLZ_MAX63(name) __builtin_clzll (name.hi)
|
||||
uint64_t q0 = l0 >> 32u;
|
||||
q0 += (uint32_t) l1;
|
||||
q0 += (uint32_t) m0;
|
||||
|
||||
/**
|
||||
* Count leading zeros in the topmost 4 bits of a 128-bit integer.
|
||||
*/
|
||||
#define ECMA_UINT128_CLZ_MAX4(name) __builtin_clzll (name.hi)
|
||||
q0 >>= 32u;
|
||||
q0 += l1 >> 32u;
|
||||
q0 += m0 >> 32u;
|
||||
q0 += (uint32_t) l2;
|
||||
q0 += (uint32_t) m1;
|
||||
q0 += (uint32_t) m0;
|
||||
|
||||
#else /* !__GNUC__ && !__clang__ */
|
||||
q0 >>= 32u;
|
||||
q0 += l2 >> 32u;
|
||||
q0 += m1 >> 32u;
|
||||
q0 += m0 >> 32u;
|
||||
q0 += (uint32_t) l3;
|
||||
q0 += (uint32_t) m2;
|
||||
q0 += (uint32_t) m1;
|
||||
q0 += (uint32_t) h0;
|
||||
|
||||
q0 >>= 32u;
|
||||
q0 += l3 >> 32u;
|
||||
q0 += m2 >> 32u;
|
||||
q0 += m1 >> 32u;
|
||||
q0 += h0 >> 32u;
|
||||
q0 += (uint32_t) m3;
|
||||
q0 += (uint32_t) m2;
|
||||
q0 += (uint32_t) h1;
|
||||
|
||||
uint64_t q1 = q0 >> 32u;
|
||||
q1 += m3 >> 32u;
|
||||
q1 += m2 >> 32u;
|
||||
q1 += h1 >> 32u;
|
||||
q1 += (uint32_t) m3;
|
||||
q1 += (uint32_t) h2;
|
||||
|
||||
uint64_t q32 = q1 >> 32u;
|
||||
q32 += m3 >> 32u;
|
||||
q32 += h2 >> 32u;
|
||||
q32 += h3;
|
||||
|
||||
num_p->lo = (q1 << 32u) | ((uint32_t) q0);
|
||||
num_p->hi = q32;
|
||||
} /* ecma_uint128_div10 */
|
||||
|
||||
/**
|
||||
* Count leading zeros in a 64-bit integer. The behaviour is undefined for 0.
|
||||
*
|
||||
* @return number of leading zeros.
|
||||
*/
|
||||
static inline int JERRY_ATTR_ALWAYS_INLINE
|
||||
inline static int JERRY_ATTR_CONST
|
||||
ecma_uint64_clz (uint64_t n) /**< integer to count leading zeros in */
|
||||
{
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
return __builtin_clzll (n);
|
||||
#else /* !defined (__GNUC__) && !defined (__clang__) */
|
||||
JERRY_ASSERT (n != 0);
|
||||
|
||||
int cnt = 0;
|
||||
uint64_t one = 0x8000000000000000ull;
|
||||
|
||||
while ((n & one) == 0)
|
||||
{
|
||||
cnt++;
|
||||
one >>= 1;
|
||||
}
|
||||
|
||||
return cnt;
|
||||
#endif /* !defined (__GNUC__) && !defined (__clang__) */
|
||||
} /* ecma_uint64_clz */
|
||||
|
||||
/**
|
||||
* Number of leading zeros in 4-bit integers.
|
||||
* Count leading zeros in the top 4 bits of a 64-bit integer.
|
||||
*
|
||||
* @return number of leading zeros in top 4 bits.
|
||||
*/
|
||||
static const uint8_t ecma_uint4_clz[] = { 4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
inline static int JERRY_ATTR_ALWAYS_INLINE JERRY_ATTR_CONST
|
||||
ecma_uint64_clz_top4 (uint64_t n) /**< integer to count leading zeros in */
|
||||
{
|
||||
static const uint8_t ecma_uint4_clz[] = { 4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
return ecma_uint4_clz[n >> 60];
|
||||
} /* ecma_uint64_clz */
|
||||
|
||||
/**
|
||||
* Count leading zeros in the topmost 64 bits of a 128-bit integer.
|
||||
* Shift required to clear 4 bits of a 64-bit integer.
|
||||
*
|
||||
* @return 0-4
|
||||
*/
|
||||
#define ECMA_UINT128_CLZ_MAX63(name) ecma_uint64_clz (name.hi)
|
||||
inline static int JERRY_ATTR_ALWAYS_INLINE JERRY_ATTR_CONST
|
||||
ecma_uint64_normalize_shift (uint64_t n) /**< integer to count leading zeros in */
|
||||
{
|
||||
static const uint8_t ecma_uint4_shift[] = { 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4 };
|
||||
|
||||
/**
|
||||
* Count leading zeros in the topmost 4 bits of a 128-bit integer.
|
||||
*/
|
||||
#define ECMA_UINT128_CLZ_MAX4(name) ecma_uint4_clz[name.hi >> 60]
|
||||
|
||||
#endif /* __GNUC__ || __clang__ */
|
||||
return ecma_uint4_shift[n >> 60];
|
||||
} /* ecma_uint64_normalize_shift */
|
||||
|
||||
/**
|
||||
* @}
|
||||
@ -285,72 +287,58 @@ static const uint8_t ecma_uint4_clz[] = { 4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0,
|
||||
* @return NaN - if the conversion fails
|
||||
* converted number - otherwise
|
||||
*/
|
||||
static ecma_number_t
|
||||
ecma_number_t
|
||||
ecma_utf8_string_to_number_by_radix (const lit_utf8_byte_t *str_p, /**< utf-8 string */
|
||||
const lit_utf8_byte_t *end_p, /**< end of utf-8 string */
|
||||
uint32_t radix) /**< radix */
|
||||
const lit_utf8_size_t string_size, /**< end of utf-8 string */
|
||||
uint32_t radix, /**< radix */
|
||||
uint32_t options) /**< option flags */
|
||||
{
|
||||
#if JERRY_ESNEXT
|
||||
bool allow_underscore = (radix & ECMA_CONVERSION_ALLOW_UNDERSCORE);
|
||||
radix &= (uint32_t) ~ECMA_CONVERSION_ALLOW_UNDERSCORE;
|
||||
#endif /* JERRY_ESNEXT */
|
||||
bool allow_underscore = (options & ECMA_CONVERSION_ALLOW_UNDERSCORE);
|
||||
#else /* !JERRY_ESNEXT */
|
||||
JERRY_UNUSED (options);
|
||||
#endif /* !JERRY_ESNEXT */
|
||||
|
||||
JERRY_ASSERT (radix == 2 || radix == 8 || radix == 16);
|
||||
JERRY_ASSERT (*str_p == LIT_CHAR_0);
|
||||
|
||||
const lit_utf8_byte_t *end_p = str_p + string_size;
|
||||
|
||||
/* Skip leading zero */
|
||||
str_p++;
|
||||
|
||||
if (radix != 8 || LEXER_TO_ASCII_LOWERCASE (*str_p) == LIT_CHAR_LOWERCASE_O)
|
||||
{
|
||||
/* Skip radix specifier */
|
||||
str_p++;
|
||||
}
|
||||
|
||||
ecma_number_t num = ECMA_NUMBER_ZERO;
|
||||
|
||||
#if JERRY_ESNEXT
|
||||
if (radix <= 8)
|
||||
while (str_p < end_p)
|
||||
{
|
||||
lit_code_point_t upper_limit = LIT_CHAR_0 + radix;
|
||||
lit_utf8_byte_t digit = *str_p++;
|
||||
|
||||
for (const lit_utf8_byte_t *iter_p = str_p; iter_p <= end_p; iter_p++)
|
||||
{
|
||||
int32_t digit_value;
|
||||
|
||||
if (*iter_p >= LIT_CHAR_0 && *iter_p < upper_limit)
|
||||
{
|
||||
digit_value = (*iter_p - LIT_CHAR_0);
|
||||
}
|
||||
else
|
||||
{
|
||||
return ecma_number_make_nan ();
|
||||
}
|
||||
|
||||
num = num * radix + (ecma_number_t) digit_value;
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
#endif /* JERRY_ESNEXT */
|
||||
|
||||
for (const lit_utf8_byte_t *iter_p = str_p; iter_p <= end_p; iter_p++)
|
||||
{
|
||||
int32_t digit_value;
|
||||
|
||||
if (*iter_p >= LIT_CHAR_0 && *iter_p <= LIT_CHAR_9)
|
||||
{
|
||||
digit_value = (*iter_p - LIT_CHAR_0);
|
||||
}
|
||||
else if (*iter_p >= LIT_CHAR_LOWERCASE_A && *iter_p <= LIT_CHAR_LOWERCASE_F)
|
||||
{
|
||||
digit_value = 10 + (*iter_p - LIT_CHAR_LOWERCASE_A);
|
||||
}
|
||||
else if (*iter_p >= LIT_CHAR_UPPERCASE_A && *iter_p <= LIT_CHAR_UPPERCASE_F)
|
||||
{
|
||||
digit_value = 10 + (*iter_p - LIT_CHAR_UPPERCASE_A);
|
||||
}
|
||||
#if JERRY_ESNEXT
|
||||
else if (*iter_p == LIT_CHAR_UNDERSCORE && allow_underscore)
|
||||
if (digit == LIT_CHAR_UNDERSCORE && allow_underscore)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
#endif /* JERRY_ESNEXT */
|
||||
else
|
||||
|
||||
if (!lit_char_is_hex_digit (digit))
|
||||
{
|
||||
return ecma_number_make_nan ();
|
||||
}
|
||||
|
||||
num = num * (ecma_number_t) radix + (ecma_number_t) digit_value;
|
||||
uint32_t value = lit_char_hex_to_int (digit);
|
||||
|
||||
if (value >= radix)
|
||||
{
|
||||
return ecma_number_make_nan ();
|
||||
}
|
||||
|
||||
num = num * radix + value;
|
||||
}
|
||||
|
||||
return num;
|
||||
@ -370,45 +358,15 @@ ecma_utf8_string_to_number (const lit_utf8_byte_t *str_p, /**< utf-8 string */
|
||||
lit_utf8_size_t str_size, /**< string size */
|
||||
uint32_t options) /**< allowing underscore option bit */
|
||||
{
|
||||
/* TODO: Check license issues */
|
||||
ecma_string_trim_helper (&str_p, &str_size);
|
||||
const lit_utf8_byte_t *end_p = str_p + str_size;
|
||||
|
||||
if (str_size == 0)
|
||||
{
|
||||
return ECMA_NUMBER_ZERO;
|
||||
}
|
||||
|
||||
ecma_string_trim_helper (&str_p, &str_size);
|
||||
const lit_utf8_byte_t *end_p = str_p + (str_size - 1);
|
||||
|
||||
if (str_size < 1)
|
||||
{
|
||||
return ECMA_NUMBER_ZERO;
|
||||
}
|
||||
|
||||
if (end_p >= str_p + 2 && str_p[0] == LIT_CHAR_0)
|
||||
{
|
||||
switch (LEXER_TO_ASCII_LOWERCASE (str_p[1]))
|
||||
{
|
||||
case LIT_CHAR_LOWERCASE_X:
|
||||
{
|
||||
return ecma_utf8_string_to_number_by_radix (str_p + 2, end_p, 16 | options);
|
||||
}
|
||||
case LIT_CHAR_LOWERCASE_O:
|
||||
{
|
||||
return ecma_utf8_string_to_number_by_radix (str_p + 2, end_p, 8 | options);
|
||||
}
|
||||
case LIT_CHAR_LOWERCASE_B:
|
||||
{
|
||||
return ecma_utf8_string_to_number_by_radix (str_p + 2, end_p, 2 | options);
|
||||
}
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool sign = false; /* positive */
|
||||
bool sign = false;
|
||||
|
||||
if (*str_p == LIT_CHAR_PLUS)
|
||||
{
|
||||
@ -416,122 +374,117 @@ ecma_utf8_string_to_number (const lit_utf8_byte_t *str_p, /**< utf-8 string */
|
||||
}
|
||||
else if (*str_p == LIT_CHAR_MINUS)
|
||||
{
|
||||
sign = true; /* negative */
|
||||
|
||||
sign = true;
|
||||
str_p++;
|
||||
}
|
||||
|
||||
if (str_p > end_p)
|
||||
if (str_p + 2 < end_p && str_p[0] == LIT_CHAR_0)
|
||||
{
|
||||
return ecma_number_make_nan ();
|
||||
uint8_t radix = lit_char_to_radix (str_p[1]);
|
||||
|
||||
if (radix != 10)
|
||||
{
|
||||
return ecma_utf8_string_to_number_by_radix (str_p, str_size, radix, options);
|
||||
}
|
||||
}
|
||||
|
||||
/* Checking if significant part of parse string is equal to "Infinity" */
|
||||
const lit_utf8_byte_t *infinity_zt_str_p = lit_get_magic_string_utf8 (LIT_MAGIC_STRING_INFINITY_UL);
|
||||
/* Check if string is equal to "Infinity". */
|
||||
const lit_utf8_byte_t *infinity_str_p = lit_get_magic_string_utf8 (LIT_MAGIC_STRING_INFINITY_UL);
|
||||
const lit_utf8_size_t infinity_length = lit_get_magic_string_size (LIT_MAGIC_STRING_INFINITY_UL);
|
||||
|
||||
JERRY_ASSERT (strlen ((const char *) infinity_zt_str_p) == 8);
|
||||
|
||||
if ((end_p - str_p) == (8 - 1) && memcmp (infinity_zt_str_p, str_p, 8) == 0)
|
||||
if ((lit_utf8_size_t) (end_p - str_p) == infinity_length && memcmp (infinity_str_p, str_p, infinity_length) == 0)
|
||||
{
|
||||
return ecma_number_make_infinity (sign);
|
||||
}
|
||||
|
||||
uint64_t fraction_uint64 = 0;
|
||||
uint32_t digits = 0;
|
||||
int32_t e = 0;
|
||||
bool digit_seen = false;
|
||||
uint64_t significand = 0;
|
||||
uint32_t digit_count = 0;
|
||||
int32_t decimal_exponent = 0;
|
||||
bool has_significand = false;
|
||||
|
||||
/* Parsing digits before dot (or before end of digits part if there is no dot in number) */
|
||||
while (str_p <= end_p)
|
||||
/* Parsing integer part */
|
||||
while (str_p < end_p)
|
||||
{
|
||||
int32_t digit_value;
|
||||
|
||||
if (*str_p >= LIT_CHAR_0 && *str_p <= LIT_CHAR_9)
|
||||
{
|
||||
digit_seen = true;
|
||||
digit_value = (*str_p - LIT_CHAR_0);
|
||||
}
|
||||
#if JERRY_ESNEXT
|
||||
else if (*str_p == LIT_CHAR_UNDERSCORE && (options & ECMA_CONVERSION_ALLOW_UNDERSCORE))
|
||||
if (*str_p == LIT_CHAR_UNDERSCORE && (options & ECMA_CONVERSION_ALLOW_UNDERSCORE))
|
||||
{
|
||||
str_p++;
|
||||
continue;
|
||||
}
|
||||
#endif /* JERRY_ESNEXT */
|
||||
else
|
||||
|
||||
if (!lit_char_is_decimal_digit (*str_p))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (digits != 0 || digit_value != 0)
|
||||
has_significand = true;
|
||||
uint32_t digit_value = (uint32_t) (*str_p++ - LIT_CHAR_0);
|
||||
|
||||
if (digit_count == 0 && digit_value == 0)
|
||||
{
|
||||
if (digits < ECMA_NUMBER_MAX_DIGITS)
|
||||
{
|
||||
fraction_uint64 = fraction_uint64 * 10 + (uint32_t) digit_value;
|
||||
digits++;
|
||||
}
|
||||
else
|
||||
{
|
||||
e++;
|
||||
}
|
||||
/* Leading zeros are omitted. */
|
||||
continue;
|
||||
}
|
||||
|
||||
str_p++;
|
||||
if (digit_count >= ECMA_NUMBER_MAX_DIGITS)
|
||||
{
|
||||
decimal_exponent++;
|
||||
continue;
|
||||
}
|
||||
|
||||
significand = significand * 10 + digit_value;
|
||||
digit_count++;
|
||||
}
|
||||
|
||||
if (str_p <= end_p && *str_p == LIT_CHAR_DOT)
|
||||
/* Parse fraction part */
|
||||
if (str_p < end_p && *str_p == LIT_CHAR_DOT)
|
||||
{
|
||||
str_p++;
|
||||
|
||||
if (!digit_seen && str_p > end_p)
|
||||
while (str_p < end_p)
|
||||
{
|
||||
return ecma_number_make_nan ();
|
||||
}
|
||||
|
||||
/* Parsing number's part that is placed after dot */
|
||||
while (str_p <= end_p)
|
||||
{
|
||||
int32_t digit_value;
|
||||
|
||||
if (*str_p >= LIT_CHAR_0 && *str_p <= LIT_CHAR_9)
|
||||
{
|
||||
digit_seen = true;
|
||||
digit_value = (*str_p - LIT_CHAR_0);
|
||||
}
|
||||
else if (*str_p == LIT_CHAR_UNDERSCORE && (options & ECMA_CONVERSION_ALLOW_UNDERSCORE))
|
||||
#if JERRY_ESNEXT
|
||||
if (*str_p == LIT_CHAR_UNDERSCORE && (options & ECMA_CONVERSION_ALLOW_UNDERSCORE))
|
||||
{
|
||||
str_p++;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
#endif /* JERRY_ESNEXT */
|
||||
|
||||
if (!lit_char_is_decimal_digit (*str_p))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (digits < ECMA_NUMBER_MAX_DIGITS)
|
||||
{
|
||||
if (digits != 0 || digit_value != 0)
|
||||
{
|
||||
fraction_uint64 = fraction_uint64 * 10 + (uint32_t) digit_value;
|
||||
digits++;
|
||||
}
|
||||
has_significand = true;
|
||||
uint32_t digit_value = (uint32_t) (*str_p++ - LIT_CHAR_0);
|
||||
|
||||
e--;
|
||||
if (digit_count == 0 && digit_value == 0)
|
||||
{
|
||||
/* Leading zeros are omitted. */
|
||||
decimal_exponent--;
|
||||
continue;
|
||||
}
|
||||
|
||||
str_p++;
|
||||
if (digit_count < ECMA_NUMBER_MAX_DIGITS)
|
||||
{
|
||||
significand = significand * 10 + digit_value;
|
||||
digit_count++;
|
||||
decimal_exponent--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Parsing exponent literal */
|
||||
int32_t e_in_lit = 0;
|
||||
bool e_in_lit_sign = false;
|
||||
|
||||
if (str_p <= end_p && (*str_p == LIT_CHAR_LOWERCASE_E || *str_p == LIT_CHAR_UPPERCASE_E))
|
||||
/* Parsing exponent */
|
||||
if (str_p < end_p && LEXER_TO_ASCII_LOWERCASE (*str_p) == LIT_CHAR_LOWERCASE_E)
|
||||
{
|
||||
str_p++;
|
||||
|
||||
if (!digit_seen || str_p > end_p)
|
||||
int32_t exponent = 0;
|
||||
int32_t exponent_sign = 1;
|
||||
|
||||
if (str_p >= end_p)
|
||||
{
|
||||
return ecma_number_make_nan ();
|
||||
}
|
||||
@ -542,81 +495,53 @@ ecma_utf8_string_to_number (const lit_utf8_byte_t *str_p, /**< utf-8 string */
|
||||
}
|
||||
else if (*str_p == LIT_CHAR_MINUS)
|
||||
{
|
||||
e_in_lit_sign = true;
|
||||
exponent_sign = -1;
|
||||
str_p++;
|
||||
}
|
||||
|
||||
if (str_p > end_p)
|
||||
if (str_p >= end_p || !lit_char_is_decimal_digit (*str_p))
|
||||
{
|
||||
return ecma_number_make_nan ();
|
||||
}
|
||||
|
||||
while (str_p <= end_p)
|
||||
while (str_p < end_p)
|
||||
{
|
||||
int32_t digit_value;
|
||||
|
||||
if (*str_p >= LIT_CHAR_0 && *str_p <= LIT_CHAR_9)
|
||||
{
|
||||
digit_value = (*str_p - LIT_CHAR_0);
|
||||
}
|
||||
#if JERRY_ESNEXT
|
||||
else if (*str_p == LIT_CHAR_UNDERSCORE && (options & ECMA_CONVERSION_ALLOW_UNDERSCORE))
|
||||
if (*str_p == LIT_CHAR_UNDERSCORE && (options & ECMA_CONVERSION_ALLOW_UNDERSCORE))
|
||||
{
|
||||
str_p++;
|
||||
continue;
|
||||
}
|
||||
#endif /* JERRY_ESNEXT */
|
||||
else
|
||||
|
||||
if (!lit_char_is_decimal_digit (*str_p))
|
||||
{
|
||||
return ecma_number_make_nan ();
|
||||
break;
|
||||
}
|
||||
|
||||
e_in_lit = e_in_lit * 10 + digit_value;
|
||||
int32_t e_check = e + (int32_t) digits - 1 + (e_in_lit_sign ? -e_in_lit : e_in_lit);
|
||||
int32_t digit_value = (*str_p++ - LIT_CHAR_0);
|
||||
exponent = exponent * 10 + digit_value;
|
||||
|
||||
if (e_check > NUMBER_MAX_DECIMAL_EXPONENT)
|
||||
if (exponent_sign * exponent > NUMBER_MAX_DECIMAL_EXPONENT)
|
||||
{
|
||||
return ecma_number_make_infinity (sign);
|
||||
}
|
||||
else if (e_check < NUMBER_MIN_DECIMAL_EXPONENT)
|
||||
|
||||
if (exponent_sign * exponent < NUMBER_MIN_DECIMAL_EXPONENT)
|
||||
{
|
||||
return sign ? -ECMA_NUMBER_ZERO : ECMA_NUMBER_ZERO;
|
||||
}
|
||||
|
||||
str_p++;
|
||||
}
|
||||
|
||||
decimal_exponent += exponent_sign * exponent;
|
||||
}
|
||||
|
||||
/* Adding value of exponent literal to exponent value */
|
||||
if (e_in_lit_sign)
|
||||
{
|
||||
e -= e_in_lit;
|
||||
}
|
||||
else
|
||||
{
|
||||
e += e_in_lit;
|
||||
}
|
||||
|
||||
bool e_sign;
|
||||
|
||||
if (e < 0)
|
||||
{
|
||||
e_sign = true;
|
||||
e = -e;
|
||||
}
|
||||
else
|
||||
{
|
||||
e_sign = false;
|
||||
}
|
||||
|
||||
if (str_p <= end_p)
|
||||
if (!has_significand || str_p < end_p)
|
||||
{
|
||||
return ecma_number_make_nan ();
|
||||
}
|
||||
|
||||
JERRY_ASSERT (str_p == end_p + 1);
|
||||
|
||||
if (fraction_uint64 == 0)
|
||||
if (significand == 0)
|
||||
{
|
||||
return sign ? -ECMA_NUMBER_ZERO : ECMA_NUMBER_ZERO;
|
||||
}
|
||||
@ -627,85 +552,93 @@ ecma_utf8_string_to_number (const lit_utf8_byte_t *str_p, /**< utf-8 string */
|
||||
*
|
||||
* Normalized: |4 bits zero|124-bit mantissa with highest bit set to 1|
|
||||
*/
|
||||
ecma_uint128_t fraction_uint128 = { 0, fraction_uint64 };
|
||||
ecma_uint128_t significand_uint128 = { .hi = significand, .lo = 0 };
|
||||
|
||||
/* Normalizing mantissa */
|
||||
int shift = 4 - ECMA_UINT128_CLZ_MAX63 (fraction_uint128);
|
||||
int shift = 4 - ecma_uint64_clz (significand_uint128.hi);
|
||||
|
||||
if (shift < 0)
|
||||
{
|
||||
ECMA_UINT128_LEFT_SHIFT_MAX63 (fraction_uint128, -shift);
|
||||
ecma_uint128_shift_left (&significand_uint128, -shift);
|
||||
}
|
||||
else
|
||||
{
|
||||
ECMA_UINT128_RIGHT_SHIFT_MAX63 (fraction_uint128, shift);
|
||||
ecma_uint128_shift_right (&significand_uint128, shift);
|
||||
}
|
||||
int32_t binary_exponent = 1 + shift;
|
||||
|
||||
if (!e_sign)
|
||||
int32_t binary_exponent = ECMA_NUMBER_FRACTION_WIDTH + shift;
|
||||
|
||||
while (decimal_exponent > 0)
|
||||
{
|
||||
/* positive or zero decimal exponent */
|
||||
JERRY_ASSERT (e >= 0);
|
||||
JERRY_ASSERT (ecma_uint64_clz (significand_uint128.hi) == 4);
|
||||
|
||||
while (e > 0)
|
||||
{
|
||||
JERRY_ASSERT (ECMA_UINT128_CLZ_MAX63 (fraction_uint128) == 4);
|
||||
ecma_uint128_mul10 (&significand_uint128);
|
||||
decimal_exponent--;
|
||||
|
||||
ECMA_UINT128_MUL10 (fraction_uint128);
|
||||
/* Re-normalizing mantissa */
|
||||
shift = ecma_uint64_normalize_shift (significand_uint128.hi);
|
||||
JERRY_ASSERT (shift >= 0 && shift <= 4);
|
||||
|
||||
e--;
|
||||
|
||||
/* Normalizing mantissa */
|
||||
shift = 4 - ECMA_UINT128_CLZ_MAX4 (fraction_uint128);
|
||||
JERRY_ASSERT (shift >= 0);
|
||||
ECMA_UINT128_RIGHT_SHIFT_MAX63 (fraction_uint128, shift);
|
||||
binary_exponent += shift;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* negative decimal exponent */
|
||||
JERRY_ASSERT (e != 0);
|
||||
|
||||
while (e > 0)
|
||||
{
|
||||
/* Denormalizing mantissa, moving highest 1 to bit 127 */
|
||||
shift = ECMA_UINT128_CLZ_MAX4 (fraction_uint128);
|
||||
JERRY_ASSERT (shift <= 4);
|
||||
ECMA_UINT128_LEFT_SHIFT_MAX63 (fraction_uint128, shift);
|
||||
binary_exponent -= shift;
|
||||
|
||||
JERRY_ASSERT (!ECMA_UINT128_IS_ZERO (fraction_uint128));
|
||||
|
||||
ECMA_UINT128_DIV10 (fraction_uint128);
|
||||
|
||||
e--;
|
||||
}
|
||||
|
||||
/* Normalizing mantissa */
|
||||
shift = 4 - ECMA_UINT128_CLZ_MAX4 (fraction_uint128);
|
||||
JERRY_ASSERT (shift >= 0);
|
||||
ECMA_UINT128_RIGHT_SHIFT_MAX63 (fraction_uint128, shift);
|
||||
ecma_uint128_shift_right (&significand_uint128, shift);
|
||||
binary_exponent += shift;
|
||||
|
||||
JERRY_ASSERT (ECMA_UINT128_CLZ_MAX63 (fraction_uint128) == 4);
|
||||
}
|
||||
|
||||
JERRY_ASSERT (!ECMA_UINT128_IS_ZERO (fraction_uint128));
|
||||
JERRY_ASSERT (ECMA_UINT128_CLZ_MAX63 (fraction_uint128) == 4);
|
||||
while (decimal_exponent < 0)
|
||||
{
|
||||
/* Denormalizing mantissa, moving highest 1 to bit 127 */
|
||||
JERRY_ASSERT (ecma_uint64_clz (significand_uint128.hi) <= 4);
|
||||
shift = ecma_uint64_clz_top4 (significand_uint128.hi);
|
||||
JERRY_ASSERT (shift >= 0 && shift <= 4);
|
||||
|
||||
ecma_uint128_shift_left (&significand_uint128, shift);
|
||||
binary_exponent -= shift;
|
||||
|
||||
ecma_uint128_div10 (&significand_uint128);
|
||||
decimal_exponent++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Preparing mantissa for conversion to 52-bit representation, converting it to:
|
||||
*
|
||||
* |11 zero bits|1|116 mantissa bits|
|
||||
*/
|
||||
ECMA_UINT128_RIGHT_SHIFT_MAX63 (fraction_uint128, 7u);
|
||||
binary_exponent += 7;
|
||||
JERRY_ASSERT (ecma_uint64_clz (significand_uint128.hi) <= 4);
|
||||
shift = 11 - ecma_uint64_clz_top4 (significand_uint128.hi);
|
||||
ecma_uint128_shift_right (&significand_uint128, shift);
|
||||
binary_exponent += shift;
|
||||
|
||||
JERRY_ASSERT (ECMA_UINT128_CLZ_MAX63 (fraction_uint128) == 11);
|
||||
JERRY_ASSERT (ecma_uint64_clz (significand_uint128.hi) == 11);
|
||||
|
||||
fraction_uint64 = ecma_round_high_to_uint64 (&fraction_uint128);
|
||||
binary_exponent += ECMA_NUMBER_EXPONENT_BIAS;
|
||||
|
||||
return ecma_number_make_from_sign_mantissa_and_exponent (sign, fraction_uint64, binary_exponent);
|
||||
/* Handle denormal numbers */
|
||||
if (binary_exponent < 1)
|
||||
{
|
||||
ecma_uint128_shift_right (&significand_uint128, -binary_exponent + 1);
|
||||
binary_exponent = 0;
|
||||
}
|
||||
|
||||
significand = ecma_round_high_to_uint64 (&significand_uint128);
|
||||
|
||||
if (significand >= 1ull << (ECMA_NUMBER_FRACTION_WIDTH + 1))
|
||||
{
|
||||
/* Rounding carried over to the most significant bit, re-normalize.
|
||||
* No need to shift mantissa right, as the low 52 bits will be 0 regardless. */
|
||||
binary_exponent++;
|
||||
}
|
||||
|
||||
if (binary_exponent >= ((1 << ECMA_NUMBER_BIASED_EXP_WIDTH) - 1))
|
||||
{
|
||||
return ecma_number_make_infinity (sign);
|
||||
}
|
||||
|
||||
/* Mask low 52 bits. */
|
||||
significand &= ((1ull << ECMA_NUMBER_FRACTION_WIDTH) - 1);
|
||||
|
||||
JERRY_ASSERT (binary_exponent < (1 << ECMA_NUMBER_BIASED_EXP_WIDTH) - 1);
|
||||
JERRY_ASSERT (significand < (1ull << ECMA_NUMBER_FRACTION_WIDTH));
|
||||
|
||||
return ecma_number_create (sign, (uint32_t) binary_exponent, significand);
|
||||
#elif !JERRY_NUMBER_TYPE_FLOAT64
|
||||
/* Less precise conversion */
|
||||
ecma_number_t num = (ecma_number_t) (uint32_t) fraction_uint64;
|
||||
@ -791,7 +724,7 @@ ecma_number_to_uint32 (ecma_number_t num) /**< ecma-number */
|
||||
|
||||
if (abs_num >= num_2_pow_32)
|
||||
{
|
||||
num_in_uint32_range = ecma_number_calc_remainder (abs_num, num_2_pow_32);
|
||||
num_in_uint32_range = ecma_number_remainder (abs_num, num_2_pow_32);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -940,8 +873,6 @@ ecma_number_to_utf8_string (ecma_number_t num, /**< ecma-number */
|
||||
return (lit_utf8_size_t) (dst_p - buffer_p);
|
||||
}
|
||||
|
||||
JERRY_ASSERT (ecma_number_get_next (ecma_number_get_prev (num)) == num);
|
||||
|
||||
/* 5. */
|
||||
uint32_t num_uint32 = ecma_number_to_uint32 (num);
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
245
jerry-core/ecma/base/ecma-helpers-number.h
Normal file
245
jerry-core/ecma/base/ecma-helpers-number.h
Normal file
@ -0,0 +1,245 @@
|
||||
/* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ECMA_HELPERS_NUMBER_H
|
||||
#define ECMA_HELPERS_NUMBER_H
|
||||
|
||||
#include "ecma-globals.h"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
/**
|
||||
* Binary representation of an ecma-number
|
||||
*/
|
||||
#if JERRY_NUMBER_TYPE_FLOAT64
|
||||
typedef uint64_t ecma_binary_num_t;
|
||||
#else /* !JERRY_NUMBER_TYPE_FLOAT64 */
|
||||
typedef uint32_t ecma_binary_num_t;
|
||||
#endif /* !JERRY_NUMBER_TYPE_FLOAT64 */
|
||||
|
||||
/**
|
||||
* Makes it possible to read/write the binary representation of an ecma_number_t
|
||||
* without strict aliasing rule violation.
|
||||
*/
|
||||
typedef union
|
||||
{
|
||||
ecma_number_t as_number; /**< ecma-number */
|
||||
ecma_binary_num_t as_binary; /**< binary representation */
|
||||
} ecma_number_accessor_t;
|
||||
|
||||
ecma_binary_num_t ecma_number_to_binary (ecma_number_t number);
|
||||
ecma_number_t ecma_number_from_binary (ecma_binary_num_t binary);
|
||||
|
||||
bool ecma_number_sign (ecma_binary_num_t binary);
|
||||
uint32_t ecma_number_biased_exp (ecma_binary_num_t binary);
|
||||
uint64_t ecma_number_fraction (ecma_binary_num_t binary);
|
||||
ecma_number_t ecma_number_create (bool sign, uint32_t biased_exp, uint64_t fraction);
|
||||
|
||||
/**
|
||||
* Maximum number of significant decimal digits that an ecma-number can store
|
||||
*/
|
||||
#if JERRY_NUMBER_TYPE_FLOAT64
|
||||
#define ECMA_NUMBER_MAX_DIGITS (19)
|
||||
#else /* !JERRY_NUMBER_TYPE_FLOAT64 */
|
||||
#define ECMA_NUMBER_MAX_DIGITS (9)
|
||||
#endif /* !JERRY_NUMBER_TYPE_FLOAT64 */
|
||||
|
||||
/**
|
||||
* Width of sign field
|
||||
*
|
||||
* See also:
|
||||
* IEEE-754 2008, 3.6, Table 3.5
|
||||
*/
|
||||
#define ECMA_NUMBER_SIGN_WIDTH (1)
|
||||
|
||||
/**
|
||||
* Width of biased exponent field
|
||||
*
|
||||
* See also:
|
||||
* IEEE-754 2008, 3.6, Table 3.5
|
||||
*/
|
||||
#if JERRY_NUMBER_TYPE_FLOAT64
|
||||
#define ECMA_NUMBER_BIASED_EXP_WIDTH (11)
|
||||
#else /* !JERRY_NUMBER_TYPE_FLOAT64 */
|
||||
#define ECMA_NUMBER_BIASED_EXP_WIDTH (8)
|
||||
#endif /* !JERRY_NUMBER_TYPE_FLOAT64 */
|
||||
|
||||
/**
|
||||
* Exponent bias
|
||||
*/
|
||||
#if JERRY_NUMBER_TYPE_FLOAT64
|
||||
#define ECMA_NUMBER_EXPONENT_BIAS (1023)
|
||||
#else /* !JERRY_NUMBER_TYPE_FLOAT64 */
|
||||
#define ECMA_NUMBER_EXPONENT_BIAS (127)
|
||||
#endif /* !JERRY_NUMBER_TYPE_FLOAT64 */
|
||||
|
||||
/**
|
||||
* Width of fraction field
|
||||
*
|
||||
* See also:
|
||||
* IEEE-754 2008, 3.6, Table 3.5
|
||||
*/
|
||||
#if JERRY_NUMBER_TYPE_FLOAT64
|
||||
#define ECMA_NUMBER_FRACTION_WIDTH (52)
|
||||
#else /* !JERRY_NUMBER_TYPE_FLOAT64 */
|
||||
#define ECMA_NUMBER_FRACTION_WIDTH (23)
|
||||
#endif /* !JERRY_NUMBER_TYPE_FLOAT64 */
|
||||
|
||||
/**
|
||||
* Sign bit in ecma-numbers
|
||||
*/
|
||||
#if JERRY_NUMBER_TYPE_FLOAT64
|
||||
#define ECMA_NUMBER_SIGN_BIT 0x8000000000000000ull
|
||||
#else /* !JERRY_NUMBER_TYPE_FLOAT64 */
|
||||
#define ECMA_NUMBER_SIGN_BIT 0x7f800000u;
|
||||
#endif /* !JERRY_NUMBER_TYPE_FLOAT64 */
|
||||
|
||||
/**
|
||||
* Binary representation of an IEEE-754 QNaN value.
|
||||
*/
|
||||
#if JERRY_NUMBER_TYPE_FLOAT64
|
||||
#define ECMA_NUMBER_BINARY_QNAN 0x7ff8000000000000ull
|
||||
#else /* !JERRY_NUMBER_TYPE_FLOAT64 */
|
||||
#define ECMA_NUMBER_BINARY_QNAN 0x7fc00000u
|
||||
#endif /* JERRY_NUMBER_TYPE_FLOAT64 */
|
||||
|
||||
/**
|
||||
* Binary representation of an IEEE-754 Infinity value.
|
||||
*/
|
||||
#if JERRY_NUMBER_TYPE_FLOAT64
|
||||
#define ECMA_NUMBER_BINARY_INF 0x7ff0000000000000ull
|
||||
#else /* !JERRY_NUMBER_TYPE_FLOAT64 */
|
||||
#define ECMA_NUMBER_BINARY_INF 0x7f800000u
|
||||
#endif /* JERRY_NUMBER_TYPE_FLOAT64 */
|
||||
|
||||
/**
|
||||
* Binary representation of an IEEE-754 zero value.
|
||||
*/
|
||||
#define ECMA_NUMBER_BINARY_ZERO 0x0ull
|
||||
|
||||
/**
|
||||
* Number.MIN_VALUE (i.e., the smallest positive value of ecma-number)
|
||||
*
|
||||
* See also: ECMA_262 v5, 15.7.3.3
|
||||
*/
|
||||
#if JERRY_NUMBER_TYPE_FLOAT64
|
||||
#define ECMA_NUMBER_MIN_VALUE ((ecma_number_t) 5e-324)
|
||||
#else /* !JERRY_NUMBER_TYPE_FLOAT64 */
|
||||
#define ECMA_NUMBER_MIN_VALUE (FLT_MIN)
|
||||
#endif /* JERRY_NUMBER_TYPE_FLOAT64 */
|
||||
|
||||
/**
|
||||
* Number.MAX_VALUE (i.e., the maximum value of ecma-number)
|
||||
*
|
||||
* See also: ECMA_262 v5, 15.7.3.2
|
||||
*/
|
||||
#if JERRY_NUMBER_TYPE_FLOAT64
|
||||
#define ECMA_NUMBER_MAX_VALUE ((ecma_number_t) 1.7976931348623157e+308)
|
||||
#else /* !JERRY_NUMBER_TYPE_FLOAT64 */
|
||||
#define ECMA_NUMBER_MAX_VALUE (FLT_MAX)
|
||||
#endif /* JERRY_NUMBER_TYPE_FLOAT64 */
|
||||
|
||||
/**
|
||||
* Number.EPSILON
|
||||
*
|
||||
* See also: ECMA_262 v6, 20.1.2.1
|
||||
*/
|
||||
#if JERRY_NUMBER_TYPE_FLOAT64
|
||||
#define ECMA_NUMBER_EPSILON ((ecma_number_t) 2.2204460492503130808472633361816e-16)
|
||||
#else /* !JERRY_NUMBER_TYPE_FLOAT64 */
|
||||
#define ECMA_NUMBER_EPSILON ((ecma_number_t) 1.1920928955078125e-7)
|
||||
#endif /* JERRY_NUMBER_TYPE_FLOAT64 */
|
||||
|
||||
/**
|
||||
* Number.MAX_SAFE_INTEGER
|
||||
*
|
||||
* See also: ECMA_262 v6, 20.1.2.6
|
||||
*/
|
||||
#if JERRY_NUMBER_TYPE_FLOAT64
|
||||
#define ECMA_NUMBER_MAX_SAFE_INTEGER ((ecma_number_t) 0x1FFFFFFFFFFFFF)
|
||||
#else /* !JERRY_NUMBER_TYPE_FLOAT64 */
|
||||
#define ECMA_NUMBER_MAX_SAFE_INTEGER ((ecma_number_t) 0xFFFFFF)
|
||||
#endif /* JERRY_NUMBER_TYPE_FLOAT64 */
|
||||
|
||||
/**
|
||||
* Number.MIN_SAFE_INTEGER
|
||||
*
|
||||
* See also: ECMA_262 v6, 20.1.2.8
|
||||
*/
|
||||
#if JERRY_NUMBER_TYPE_FLOAT64
|
||||
#define ECMA_NUMBER_MIN_SAFE_INTEGER ((ecma_number_t) -0x1FFFFFFFFFFFFF)
|
||||
#else /* !JERRY_NUMBER_TYPE_FLOAT64 */
|
||||
#define ECMA_NUMBER_MIN_SAFE_INTEGER ((ecma_number_t) -0xFFFFFF)
|
||||
#endif /* JERRY_NUMBER_TYPE_FLOAT64 */
|
||||
|
||||
/**
|
||||
* Number.MAX_VALUE exponent part
|
||||
*/
|
||||
#if JERRY_NUMBER_TYPE_FLOAT64
|
||||
#define NUMBER_MAX_DECIMAL_EXPONENT 308
|
||||
#else /* !JERRY_NUMBER_TYPE_FLOAT64 */
|
||||
#define NUMBER_MAX_DECIMAL_EXPONENT 38
|
||||
#endif /* JERRY_NUMBER_TYPE_FLOAT64 */
|
||||
|
||||
/**
|
||||
* Number.MIN_VALUE exponent part
|
||||
*/
|
||||
#if JERRY_NUMBER_TYPE_FLOAT64
|
||||
#define NUMBER_MIN_DECIMAL_EXPONENT -324
|
||||
#else /* !JERRY_NUMBER_TYPE_FLOAT64 */
|
||||
#define NUMBER_MIN_DECIMAL_EXPONENT -45
|
||||
#endif /* JERRY_NUMBER_TYPE_FLOAT64 */
|
||||
|
||||
/**
|
||||
* Euler number
|
||||
*/
|
||||
#define ECMA_NUMBER_E ((ecma_number_t) 2.7182818284590452354)
|
||||
|
||||
/**
|
||||
* Natural logarithm of 10
|
||||
*/
|
||||
#define ECMA_NUMBER_LN10 ((ecma_number_t) 2.302585092994046)
|
||||
|
||||
/**
|
||||
* Natural logarithm of 2
|
||||
*/
|
||||
#define ECMA_NUMBER_LN2 ((ecma_number_t) 0.6931471805599453)
|
||||
|
||||
/**
|
||||
* Logarithm base 2 of the Euler number
|
||||
*/
|
||||
#define ECMA_NUMBER_LOG2E ((ecma_number_t) 1.4426950408889634)
|
||||
|
||||
/**
|
||||
* Logarithm base 10 of the Euler number
|
||||
*/
|
||||
#define ECMA_NUMBER_LOG10E ((ecma_number_t) 0.4342944819032518)
|
||||
|
||||
/**
|
||||
* Pi number
|
||||
*/
|
||||
#define ECMA_NUMBER_PI ((ecma_number_t) 3.1415926535897932)
|
||||
|
||||
/**
|
||||
* Square root of 0.5
|
||||
*/
|
||||
#define ECMA_NUMBER_SQRT_1_2 ((ecma_number_t) 0.7071067811865476)
|
||||
|
||||
/**
|
||||
* Square root of 2
|
||||
*/
|
||||
#define ECMA_NUMBER_SQRT2 ((ecma_number_t) 1.4142135623730951)
|
||||
|
||||
#endif /* !ECMA_HELPERS_NUMBER_H */
|
||||
@ -18,6 +18,7 @@
|
||||
#include "ecma-exceptions.h"
|
||||
#include "ecma-gc.h"
|
||||
#include "ecma-globals.h"
|
||||
#include "ecma-helpers-number.h"
|
||||
#include "ecma-helpers.h"
|
||||
|
||||
#include "jcontext.h"
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
#include "ecma-function-object.h"
|
||||
#include "ecma-gc.h"
|
||||
#include "ecma-globals.h"
|
||||
#include "ecma-helpers-number.h"
|
||||
#include "ecma-helpers.h"
|
||||
|
||||
#include "jrt-bit-fields.h"
|
||||
@ -536,7 +537,7 @@ ecma_make_float_value (ecma_number_t *ecma_num_p) /**< pointer to the float numb
|
||||
*
|
||||
* @return ecma-value
|
||||
*/
|
||||
extern inline ecma_value_t JERRY_ATTR_ALWAYS_INLINE
|
||||
extern inline ecma_value_t JERRY_ATTR_ALWAYS_INLINE JERRY_ATTR_CONST
|
||||
ecma_make_nan_value (void)
|
||||
{
|
||||
return ecma_create_float_number (ecma_number_make_nan ());
|
||||
@ -550,13 +551,7 @@ ecma_make_nan_value (void)
|
||||
static inline bool JERRY_ATTR_CONST JERRY_ATTR_ALWAYS_INLINE
|
||||
ecma_is_number_equal_to_positive_zero (ecma_number_t ecma_number) /**< number */
|
||||
{
|
||||
ecma_number_accessor_t u;
|
||||
u.as_ecma_number_t = ecma_number;
|
||||
#if !JERRY_NUMBER_TYPE_FLOAT64
|
||||
return u.as_uint32_t == 0;
|
||||
#else /* JERRY_NUMBER_TYPE_FLOAT64 */
|
||||
return u.as_uint64_t == 0;
|
||||
#endif /* !JERRY_NUMBER_TYPE_FLOAT64 */
|
||||
return ecma_number_to_binary (ecma_number) == ECMA_NUMBER_BINARY_ZERO;
|
||||
} /* ecma_is_number_equal_to_positive_zero */
|
||||
|
||||
/**
|
||||
|
||||
@ -394,8 +394,6 @@ ecma_string_t *ecma_stringbuilder_finalize (ecma_stringbuilder_t *builder_p);
|
||||
void ecma_stringbuilder_destroy (ecma_stringbuilder_t *builder_p);
|
||||
|
||||
/* ecma-helpers-number.c */
|
||||
ecma_number_t ecma_number_pack (bool sign, uint32_t biased_exp, uint64_t fraction);
|
||||
void ecma_number_unpack (ecma_number_t num, bool *sign_p, uint32_t *biased_exp_p, uint64_t *fraction_p);
|
||||
ecma_number_t ecma_number_make_nan (void);
|
||||
ecma_number_t ecma_number_make_infinity (bool sign);
|
||||
bool ecma_number_is_nan (ecma_number_t num);
|
||||
@ -403,11 +401,10 @@ bool ecma_number_is_negative (ecma_number_t num);
|
||||
bool ecma_number_is_zero (ecma_number_t num);
|
||||
bool ecma_number_is_infinity (ecma_number_t num);
|
||||
bool ecma_number_is_finite (ecma_number_t num);
|
||||
ecma_number_t ecma_number_make_from_sign_mantissa_and_exponent (bool sign, uint64_t mantissa, int32_t exponent);
|
||||
ecma_number_t ecma_number_get_prev (ecma_number_t num);
|
||||
ecma_number_t ecma_number_get_next (ecma_number_t num);
|
||||
ecma_number_t ecma_number_trunc (ecma_number_t num);
|
||||
ecma_number_t ecma_number_calc_remainder (ecma_number_t left_num, ecma_number_t right_num);
|
||||
ecma_number_t ecma_number_remainder (ecma_number_t left_num, ecma_number_t right_num);
|
||||
ecma_number_t ecma_number_pow (ecma_number_t x, ecma_number_t y);
|
||||
ecma_value_t
|
||||
ecma_number_parse_int (const lit_utf8_byte_t *string_buff, lit_utf8_size_t string_buff_size, ecma_value_t radix);
|
||||
@ -538,6 +535,10 @@ bool ecma_delete_native_pointer_property (ecma_object_t *obj_p, const jerry_obje
|
||||
|
||||
/* ecma-helpers-conversion.c */
|
||||
ecma_number_t ecma_utf8_string_to_number (const lit_utf8_byte_t *str_p, lit_utf8_size_t str_size, uint32_t option);
|
||||
ecma_number_t ecma_utf8_string_to_number_by_radix (const lit_utf8_byte_t *str_p,
|
||||
lit_utf8_size_t str_size,
|
||||
uint32_t radix,
|
||||
uint32_t option);
|
||||
lit_utf8_size_t ecma_uint32_to_utf8_string (uint32_t value, lit_utf8_byte_t *out_buffer_p, lit_utf8_size_t buffer_size);
|
||||
uint32_t ecma_number_to_uint32 (ecma_number_t num);
|
||||
int32_t ecma_number_to_int32 (ecma_number_t num);
|
||||
|
||||
@ -23,6 +23,7 @@
|
||||
#include "ecma-function-object.h"
|
||||
#include "ecma-gc.h"
|
||||
#include "ecma-globals.h"
|
||||
#include "ecma-helpers-number.h"
|
||||
#include "ecma-helpers.h"
|
||||
#include "ecma-objects.h"
|
||||
#include "ecma-string-object.h"
|
||||
|
||||
@ -677,7 +677,7 @@ ecma_builtin_date_utc (const ecma_value_t args[], /**< arguments list */
|
||||
|
||||
if (args_number < required_args_number)
|
||||
{
|
||||
return ecma_make_number_value (ecma_number_make_nan ());
|
||||
return ecma_make_nan_value ();
|
||||
}
|
||||
|
||||
ecma_number_t tv;
|
||||
@ -868,7 +868,7 @@ ecma_builtin_date_dispatch_routine (uint8_t builtin_routine_id, /**< built-in wi
|
||||
{
|
||||
if (arguments_number < 1)
|
||||
{
|
||||
return ecma_make_number_value (ecma_number_make_nan ());
|
||||
return ecma_make_nan_value ();
|
||||
}
|
||||
|
||||
ecma_string_t *str_p = ecma_op_to_string (arguments_list_p[0]);
|
||||
|
||||
@ -15,6 +15,7 @@
|
||||
|
||||
#include "ecma-builtin-helpers.h"
|
||||
#include "ecma-globals.h"
|
||||
#include "ecma-helpers-number.h"
|
||||
|
||||
/**
|
||||
* Function used to merge two arrays for merge sort.
|
||||
|
||||
@ -22,6 +22,7 @@
|
||||
#include "ecma-exceptions.h"
|
||||
#include "ecma-function-object.h"
|
||||
#include "ecma-gc.h"
|
||||
#include "ecma-helpers-number.h"
|
||||
#include "ecma-helpers.h"
|
||||
#include "ecma-objects.h"
|
||||
|
||||
|
||||
@ -22,7 +22,6 @@
|
||||
#include "ecma-gc.h"
|
||||
#include "ecma-globals.h"
|
||||
#include "ecma-helpers.h"
|
||||
#include "ecma-number-arithmetic.h"
|
||||
#include "ecma-objects-general.h"
|
||||
#include "ecma-objects.h"
|
||||
|
||||
@ -438,30 +437,37 @@ ecma_builtin_math_dispatch_routine (uint8_t builtin_routine_id, /**< built-in wi
|
||||
#endif /* JERRY_ESNEXT */
|
||||
case ECMA_MATH_OBJECT_ROUND:
|
||||
{
|
||||
if (ecma_number_is_nan (x) || ecma_number_is_zero (x) || ecma_number_is_infinity (x) || fmod (x, 1.0) == 0)
|
||||
if (ecma_number_is_nan (x) || ecma_number_is_zero (x) || ecma_number_is_infinity (x))
|
||||
{
|
||||
/* Do nothing. */
|
||||
break;
|
||||
}
|
||||
else if (ecma_number_is_negative (x) && x >= -ECMA_NUMBER_HALF)
|
||||
{
|
||||
x = -ECMA_NUMBER_ZERO;
|
||||
}
|
||||
else
|
||||
{
|
||||
const ecma_number_t up_half = x + ECMA_NUMBER_HALF;
|
||||
const ecma_number_t down_half = x - ECMA_NUMBER_HALF;
|
||||
const ecma_number_t up_rounded = up_half - ecma_op_number_remainder (up_half, ECMA_NUMBER_ONE);
|
||||
const ecma_number_t down_rounded = down_half - ecma_op_number_remainder (down_half, ECMA_NUMBER_ONE);
|
||||
|
||||
if (up_rounded - x <= x - down_rounded)
|
||||
ecma_number_t fraction = fmod (x, ECMA_NUMBER_ONE);
|
||||
|
||||
if (ecma_number_is_zero (fraction))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (ecma_number_is_negative (x))
|
||||
{
|
||||
if (x >= -ECMA_NUMBER_HALF)
|
||||
{
|
||||
x = up_rounded;
|
||||
x = -ECMA_NUMBER_ZERO;
|
||||
break;
|
||||
}
|
||||
else
|
||||
|
||||
if (fraction < -ECMA_NUMBER_HALF)
|
||||
{
|
||||
x = down_rounded;
|
||||
x -= ECMA_NUMBER_HALF;
|
||||
}
|
||||
}
|
||||
else if (fraction >= ECMA_NUMBER_HALF)
|
||||
{
|
||||
x += ECMA_NUMBER_HALF;
|
||||
}
|
||||
|
||||
x = ecma_number_trunc (x);
|
||||
break;
|
||||
}
|
||||
case ECMA_MATH_OBJECT_SIN:
|
||||
|
||||
@ -21,6 +21,7 @@
|
||||
#include "ecma-exceptions.h"
|
||||
#include "ecma-gc.h"
|
||||
#include "ecma-globals.h"
|
||||
#include "ecma-helpers-number.h"
|
||||
#include "ecma-helpers.h"
|
||||
#include "ecma-objects.h"
|
||||
#include "ecma-string-object.h"
|
||||
@ -132,6 +133,11 @@ ecma_builtin_number_prototype_helper_round (lit_utf8_byte_t *digits_p, /**< [in,
|
||||
return (lit_utf8_size_t) round_num;
|
||||
} /* ecma_builtin_number_prototype_helper_round */
|
||||
|
||||
/**
|
||||
* Size of Number toString digit buffers.
|
||||
*/
|
||||
#define NUMBER_TO_STRING_MAX_DIGIT_COUNT 64u
|
||||
|
||||
/**
|
||||
* The Number.prototype object's 'toString' and 'toLocaleString' routines
|
||||
*
|
||||
@ -176,249 +182,130 @@ ecma_builtin_number_prototype_object_to_string (ecma_number_t this_arg_number, /
|
||||
return ecma_make_string_value (ret_str_p);
|
||||
}
|
||||
|
||||
int buff_size = 0;
|
||||
|
||||
uint8_t integer_digits[NUMBER_TO_STRING_MAX_DIGIT_COUNT];
|
||||
uint8_t fraction_digits[NUMBER_TO_STRING_MAX_DIGIT_COUNT];
|
||||
uint32_t integer_zeros = 0;
|
||||
uint32_t fraction_zeros = 0;
|
||||
bool is_number_negative = false;
|
||||
|
||||
if (ecma_number_is_negative (this_arg_number))
|
||||
{
|
||||
/* ecma_number_to_decimal can't handle negative numbers, so we get rid of the sign. */
|
||||
this_arg_number = -this_arg_number;
|
||||
is_number_negative = true;
|
||||
|
||||
/* Add space for the sign in the result. */
|
||||
buff_size += 1;
|
||||
}
|
||||
|
||||
/* Decompose the number. */
|
||||
lit_utf8_byte_t digits[ECMA_MAX_CHARS_IN_STRINGIFIED_NUMBER];
|
||||
int32_t exponent;
|
||||
lit_utf8_size_t digit_count = ecma_number_to_decimal (this_arg_number, digits, &exponent);
|
||||
ecma_number_t integer_part = floor (this_arg_number);
|
||||
ecma_number_t fraction_part = this_arg_number - integer_part;
|
||||
|
||||
/*
|
||||
* The 'exponent' given by 'ecma_number_to_decimal' specifies where the decimal point is located
|
||||
* compared to the first digit in 'digits'.
|
||||
* For example: 120 -> '12', exp: 3 and 0.012 -> '12', exp: -1
|
||||
* We convert it to be location of the decimal point compared to the last digit of 'digits':
|
||||
* 120 -> 12 * 10^1 and 0.012 -> 12 * 10^-3
|
||||
*/
|
||||
exponent = exponent - (int32_t) digit_count;
|
||||
uint8_t *integer_cursor_p = integer_digits + NUMBER_TO_STRING_MAX_DIGIT_COUNT;
|
||||
uint8_t *fraction_cursor_p = fraction_digits;
|
||||
|
||||
/* 'magnitude' will be the magnitude of the number in the specific radix. */
|
||||
int magnitude;
|
||||
int required_digits;
|
||||
if (exponent >= 0)
|
||||
if (fraction_part > 0.0)
|
||||
{
|
||||
/*
|
||||
* If the exponent is non-negative that means we won't have a fractional part, and can calculate
|
||||
* exactly how many digits we will have. This could be done via a mathematic formula, but in rare
|
||||
* cases that can cause incorrect results due to precision issues, so we use a loop instead.
|
||||
*/
|
||||
magnitude = 0;
|
||||
ecma_number_t counter = this_arg_number;
|
||||
while (counter >= radix)
|
||||
uint8_t digit;
|
||||
ecma_number_t precision = (ecma_number_get_next (this_arg_number) - this_arg_number) * 0.5f;
|
||||
precision = JERRY_MAX (precision, ECMA_NUMBER_MIN_VALUE);
|
||||
|
||||
do
|
||||
{
|
||||
counter /= radix;
|
||||
magnitude++;
|
||||
}
|
||||
fraction_part *= radix;
|
||||
precision *= radix;
|
||||
|
||||
/*
|
||||
* The magnitude will only tell us how many digits we have after the first one, so we add one extra.
|
||||
* In this case we won't be needing a radix point, so we don't need to worry about space for it.
|
||||
*/
|
||||
required_digits = magnitude + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* We can't know exactly how many digits we will need, since the number may be non-terminating in the
|
||||
* new radix, so we will have to estimate it. We do this by first calculating how many zeros we will
|
||||
* need in the specific radix before we hit a significant digit. This is calculated from the decimal
|
||||
* exponent, which we negate so that we get a positive number in the end.
|
||||
*/
|
||||
magnitude = (int) floor ((log (10) / log (radix)) * -exponent);
|
||||
digit = (uint8_t) floor (fraction_part);
|
||||
|
||||
/*
|
||||
* We also need to add space for significant digits. The worst case is radix == 2, since this will
|
||||
* require the most digits. In this case, the upper limit to the number of significant digits we can have is
|
||||
* ECMA_NUMBER_FRACTION_WIDTH + 1. This should be sufficient for any number.
|
||||
*/
|
||||
required_digits = magnitude + ECMA_NUMBER_FRACTION_WIDTH + 1;
|
||||
|
||||
/*
|
||||
* We add an exta slot for the radix point. It is also likely that we will need extra space for a
|
||||
* leading zero before the radix point. It's better to add space for that here as well, even if we may not
|
||||
* need it, since later we won't be able to do so.
|
||||
*/
|
||||
buff_size += 2;
|
||||
}
|
||||
|
||||
/*
|
||||
* Here we normalize the number so that it is as close to 0 as possible, which will prevent us from losing
|
||||
* precision in case of extreme numbers when we later split the number into integer and fractional parts.
|
||||
* This has to be done in the specific radix, otherwise it messes up the result, so we use magnitude instead.
|
||||
*/
|
||||
if (exponent > 0)
|
||||
{
|
||||
for (int i = 0; i < magnitude; i++)
|
||||
{
|
||||
this_arg_number /= radix;
|
||||
}
|
||||
}
|
||||
else if (exponent < 0)
|
||||
{
|
||||
for (int i = 0; i < magnitude; i++)
|
||||
{
|
||||
this_arg_number *= radix;
|
||||
}
|
||||
}
|
||||
|
||||
/* Split the number into an integer and a fractional part, since we have to handle them separately. */
|
||||
uint64_t whole = (uint64_t) this_arg_number;
|
||||
ecma_number_t fraction = this_arg_number - (ecma_number_t) whole;
|
||||
|
||||
bool should_round = false;
|
||||
if (!ecma_number_is_zero (fraction) && exponent >= 0)
|
||||
{
|
||||
/*
|
||||
* If the exponent is non-negative, and we get a non-zero fractional part, that means
|
||||
* the normalization might have introduced a small error, in which case we have to correct it by rounding.
|
||||
* We'll add one extra significant digit which we will later use to round.
|
||||
*/
|
||||
required_digits += 1;
|
||||
should_round = true;
|
||||
}
|
||||
|
||||
/* Get the total required buffer size and allocate the buffer. */
|
||||
buff_size += required_digits;
|
||||
ecma_value_t ret_value;
|
||||
JMEM_DEFINE_LOCAL_ARRAY (buff, buff_size, lit_utf8_byte_t);
|
||||
int buff_index = 0;
|
||||
|
||||
/* Calculate digits for whole part. */
|
||||
while (whole > 0)
|
||||
{
|
||||
JERRY_ASSERT (buff_index < buff_size && buff_index < required_digits);
|
||||
buff[buff_index++] = (lit_utf8_byte_t) (whole % radix);
|
||||
whole /= radix;
|
||||
}
|
||||
|
||||
/* The digits are backwards, we need to reverse them. */
|
||||
for (int i = 0; i < buff_index / 2; i++)
|
||||
{
|
||||
lit_utf8_byte_t swap = buff[i];
|
||||
buff[i] = buff[buff_index - i - 1];
|
||||
buff[buff_index - i - 1] = swap;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate where we have to put the radix point relative to the beginning of
|
||||
* the new digits. If the exponent is non-negative this will be right after the number.
|
||||
*/
|
||||
int point = exponent >= 0 ? magnitude + 1 : buff_index - magnitude;
|
||||
|
||||
if (point < 0)
|
||||
{
|
||||
/*
|
||||
* In this case the radix point will be before the first digit,
|
||||
* so we need to leave space for leading zeros.
|
||||
*/
|
||||
JERRY_ASSERT (exponent < 0);
|
||||
required_digits += point;
|
||||
}
|
||||
|
||||
JERRY_ASSERT (required_digits <= buff_size);
|
||||
|
||||
/* Calculate digits for fractional part. */
|
||||
while (buff_index < required_digits)
|
||||
{
|
||||
fraction *= radix;
|
||||
lit_utf8_byte_t digit = (lit_utf8_byte_t) floor (fraction);
|
||||
|
||||
buff[buff_index++] = digit;
|
||||
fraction -= (ecma_number_t) floor (fraction);
|
||||
}
|
||||
|
||||
if (should_round)
|
||||
{
|
||||
/* Consume last digit for rounding. */
|
||||
buff_index--;
|
||||
if (buff[buff_index] > radix / 2)
|
||||
{
|
||||
/* We should be rounding up. */
|
||||
buff[buff_index - 1]++;
|
||||
|
||||
/* Propagate carry forward in the digits. */
|
||||
for (int i = buff_index - 1; i > 0 && buff[i] >= radix; i--)
|
||||
if (digit == 0 && fraction_cursor_p == fraction_digits)
|
||||
{
|
||||
buff[i] = (lit_utf8_byte_t) (buff[i] - radix);
|
||||
buff[i - 1]++;
|
||||
fraction_zeros++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (buff[0] >= radix)
|
||||
JERRY_ASSERT (fraction_cursor_p < fraction_digits + NUMBER_TO_STRING_MAX_DIGIT_COUNT);
|
||||
*fraction_cursor_p++ = digit;
|
||||
fraction_part -= (ecma_number_t) digit;
|
||||
} while (fraction_part >= precision);
|
||||
|
||||
/* Round to even */
|
||||
if (fraction_part > 0.5 || (fraction_part == 0.5 && (digit & 1) != 0))
|
||||
{
|
||||
/* Add carry and remove overflowing trailing digits */
|
||||
while (true)
|
||||
{
|
||||
/*
|
||||
* Carry propagated over the whole number, we need to add a new leading digit.
|
||||
* We can use the place of the original rounded digit, we just need to shift everything
|
||||
* right by one.
|
||||
*/
|
||||
memmove (buff + 1, buff, (size_t) buff_index);
|
||||
buff_index++;
|
||||
buff[0] = 1;
|
||||
(*(--fraction_cursor_p))++;
|
||||
|
||||
if (*fraction_cursor_p < radix)
|
||||
{
|
||||
/* Re-adjust cursor to point after the last significant digit */
|
||||
fraction_cursor_p++;
|
||||
break;
|
||||
}
|
||||
|
||||
if (fraction_cursor_p == fraction_digits)
|
||||
{
|
||||
/* Carry overflowed to integer part */
|
||||
integer_part += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Remove trailing zeros. */
|
||||
while (buff_index - 1 > point && buff[buff_index - 1] == 0)
|
||||
{
|
||||
buff_index--;
|
||||
}
|
||||
|
||||
/* Add leading zeros in case place of radix point is negative. */
|
||||
if (point <= 0)
|
||||
{
|
||||
/* We will have 'point' amount of zeros after the radix point, and +1 before. */
|
||||
int zero_count = -point + 1;
|
||||
memmove (buff + zero_count, buff, (size_t) buff_index);
|
||||
buff_index += zero_count;
|
||||
|
||||
for (int i = 0; i < zero_count; i++)
|
||||
/* Convert fraction digits to characters. */
|
||||
for (uint8_t *digit_p = fraction_digits; digit_p < fraction_cursor_p; digit_p++)
|
||||
{
|
||||
buff[i] = 0;
|
||||
*digit_p = digit_chars[*digit_p];
|
||||
}
|
||||
|
||||
/* We now need to place the radix point after the first zero. */
|
||||
point = 1;
|
||||
}
|
||||
|
||||
/* Convert digits to characters. */
|
||||
for (int i = 0; i < buff_index; i++)
|
||||
while (ecma_number_biased_exp (ecma_number_to_binary (integer_part / radix))
|
||||
> ECMA_NUMBER_EXPONENT_BIAS + ECMA_NUMBER_FRACTION_WIDTH)
|
||||
{
|
||||
buff[i] = digit_chars[buff[i]];
|
||||
integer_zeros++;
|
||||
integer_part /= radix;
|
||||
}
|
||||
|
||||
/* Place radix point to the required position. */
|
||||
if (point < buff_index)
|
||||
uint64_t integer_u64 = (uint64_t) integer_part;
|
||||
|
||||
do
|
||||
{
|
||||
memmove (buff + point + 1, buff + point, (size_t) (buff_index - point));
|
||||
buff[point] = '.';
|
||||
buff_index++;
|
||||
}
|
||||
uint64_t remainder = integer_u64 % radix;
|
||||
*(--integer_cursor_p) = (uint8_t) digit_chars[remainder];
|
||||
|
||||
integer_u64 /= radix;
|
||||
} while (integer_u64 > 0);
|
||||
|
||||
const uint32_t integer_digit_count =
|
||||
(uint32_t) (integer_digits + NUMBER_TO_STRING_MAX_DIGIT_COUNT - integer_cursor_p);
|
||||
JERRY_ASSERT (integer_digit_count > 0);
|
||||
|
||||
ecma_stringbuilder_t builder = ecma_stringbuilder_create ();
|
||||
|
||||
/* Add negative sign if necessary. */
|
||||
if (is_number_negative)
|
||||
{
|
||||
memmove (buff + 1, buff, (size_t) buff_index);
|
||||
buff[0] = '-';
|
||||
buff_index++;
|
||||
ecma_stringbuilder_append_byte (&builder, LIT_CHAR_MINUS);
|
||||
}
|
||||
|
||||
JERRY_ASSERT (buff_index <= buff_size);
|
||||
ecma_string_t *str_p = ecma_new_ecma_string_from_utf8 (buff, (lit_utf8_size_t) buff_index);
|
||||
ret_value = ecma_make_string_value (str_p);
|
||||
JMEM_FINALIZE_LOCAL_ARRAY (buff);
|
||||
ecma_stringbuilder_append_raw (&builder, integer_cursor_p, integer_digit_count);
|
||||
|
||||
return ret_value;
|
||||
while (integer_zeros--)
|
||||
{
|
||||
ecma_stringbuilder_append_byte (&builder, LIT_CHAR_0);
|
||||
}
|
||||
|
||||
if (fraction_cursor_p != fraction_digits)
|
||||
{
|
||||
ecma_stringbuilder_append_byte (&builder, LIT_CHAR_DOT);
|
||||
|
||||
while (fraction_zeros--)
|
||||
{
|
||||
ecma_stringbuilder_append_byte (&builder, LIT_CHAR_0);
|
||||
}
|
||||
|
||||
const uint32_t fraction_digit_count = (uint32_t) (fraction_cursor_p - fraction_digits);
|
||||
JERRY_ASSERT (fraction_digit_count > 0);
|
||||
|
||||
ecma_stringbuilder_append_raw (&builder, fraction_digits, fraction_digit_count);
|
||||
}
|
||||
|
||||
return ecma_make_string_value (ecma_stringbuilder_finalize (&builder));
|
||||
} /* ecma_builtin_number_prototype_object_to_string */
|
||||
|
||||
/**
|
||||
|
||||
@ -22,6 +22,7 @@
|
||||
#include "ecma-exceptions.h"
|
||||
#include "ecma-gc.h"
|
||||
#include "ecma-globals.h"
|
||||
#include "ecma-helpers-number.h"
|
||||
#include "ecma-helpers.h"
|
||||
#include "ecma-number-object.h"
|
||||
#include "ecma-objects.h"
|
||||
|
||||
@ -20,6 +20,7 @@
|
||||
#include "ecma-function-object.h"
|
||||
#include "ecma-gc.h"
|
||||
#include "ecma-globals.h"
|
||||
#include "ecma-helpers-number.h"
|
||||
#include "ecma-helpers.h"
|
||||
#include "ecma-objects.h"
|
||||
|
||||
|
||||
@ -24,7 +24,6 @@
|
||||
#include "ecma-globals.h"
|
||||
#include "ecma-helpers.h"
|
||||
#include "ecma-iterator-object.h"
|
||||
#include "ecma-number-arithmetic.h"
|
||||
#include "ecma-objects-general.h"
|
||||
#include "ecma-objects.h"
|
||||
#include "ecma-property-hashmap.h"
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
|
||||
#include "ecma-big-uint.h"
|
||||
#include "ecma-exceptions.h"
|
||||
#include "ecma-helpers-number.h"
|
||||
#include "ecma-helpers.h"
|
||||
#include "ecma-objects.h"
|
||||
|
||||
@ -85,21 +86,10 @@ ecma_bigint_parse_string (const lit_utf8_byte_t *string_p, /**< string represena
|
||||
|
||||
if (size >= 3 && string_p[0] == LIT_CHAR_0)
|
||||
{
|
||||
if (string_p[1] == LIT_CHAR_LOWERCASE_X || string_p[1] == LIT_CHAR_UPPERCASE_X)
|
||||
radix = lit_char_to_radix (string_p[1]);
|
||||
|
||||
if (radix != 10)
|
||||
{
|
||||
radix = 16;
|
||||
string_p += 2;
|
||||
size -= 2;
|
||||
}
|
||||
else if (string_p[1] == LIT_CHAR_LOWERCASE_O || string_p[1] == LIT_CHAR_UPPERCASE_O)
|
||||
{
|
||||
radix = 8;
|
||||
string_p += 2;
|
||||
size -= 2;
|
||||
}
|
||||
else if (string_p[1] == LIT_CHAR_LOWERCASE_B || string_p[1] == LIT_CHAR_UPPERCASE_B)
|
||||
{
|
||||
radix = 2;
|
||||
string_p += 2;
|
||||
size -= 2;
|
||||
}
|
||||
@ -292,17 +282,15 @@ static uint32_t
|
||||
ecma_bigint_number_to_digits (ecma_number_t number, /**< ecma number */
|
||||
ecma_bigint_digit_t *digits_p) /**< [out] BigInt digits */
|
||||
{
|
||||
uint32_t biased_exp;
|
||||
uint64_t fraction;
|
||||
|
||||
ecma_number_unpack (number, NULL, &biased_exp, &fraction);
|
||||
|
||||
if (biased_exp == 0 && fraction == 0)
|
||||
if (ecma_number_is_zero (number))
|
||||
{
|
||||
/* Number is zero. */
|
||||
return ECMA_BIGINT_NUMBER_TO_DIGITS_SET_DIGITS (0);
|
||||
}
|
||||
|
||||
ecma_binary_num_t binary = ecma_number_to_binary (number);
|
||||
uint32_t biased_exp = ecma_number_biased_exp (binary);
|
||||
uint64_t fraction = ecma_number_fraction (binary);
|
||||
|
||||
if (biased_exp < ((1 << (ECMA_NUMBER_BIASED_EXP_WIDTH - 1)) - 1))
|
||||
{
|
||||
/* Number is less than 1. */
|
||||
@ -618,7 +606,7 @@ ecma_bigint_to_number (ecma_value_t value) /**< BigInt value */
|
||||
|
||||
if (biased_exp < (1u << ECMA_NUMBER_BIASED_EXP_WIDTH) - 1)
|
||||
{
|
||||
result = ecma_number_pack (sign, biased_exp, fraction);
|
||||
result = ecma_number_create (sign, biased_exp, fraction);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@ -29,6 +29,7 @@
|
||||
#include "ecma-function-object.h"
|
||||
#include "ecma-gc.h"
|
||||
#include "ecma-globals.h"
|
||||
#include "ecma-helpers-number.h"
|
||||
#include "ecma-helpers.h"
|
||||
#include "ecma-number-object.h"
|
||||
#include "ecma-objects-general.h"
|
||||
|
||||
@ -24,7 +24,6 @@
|
||||
#include "ecma-gc.h"
|
||||
#include "ecma-globals.h"
|
||||
#include "ecma-helpers.h"
|
||||
#include "ecma-number-arithmetic.h"
|
||||
#include "ecma-objects-general.h"
|
||||
#include "ecma-objects.h"
|
||||
|
||||
|
||||
@ -1,56 +0,0 @@
|
||||
/* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "ecma-number-arithmetic.h"
|
||||
|
||||
#include "ecma-globals.h"
|
||||
#include "ecma-helpers.h"
|
||||
|
||||
/** \addtogroup ecma ECMA
|
||||
* @{
|
||||
*
|
||||
* \addtogroup numberarithmetic ECMA number arithmetic operations
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* ECMA-defined number remainder calculation.
|
||||
*
|
||||
* See also:
|
||||
* ECMA-262 v5, 11.5.3
|
||||
*
|
||||
* @return number - calculated remainder.
|
||||
*/
|
||||
ecma_number_t
|
||||
ecma_op_number_remainder (ecma_number_t left_num, /**< left operand */
|
||||
ecma_number_t right_num) /**< right operand */
|
||||
{
|
||||
if (ecma_number_is_nan (left_num) || ecma_number_is_nan (right_num) || ecma_number_is_infinity (left_num)
|
||||
|| ecma_number_is_zero (right_num))
|
||||
{
|
||||
return ecma_number_make_nan ();
|
||||
}
|
||||
else if (ecma_number_is_infinity (right_num) || (ecma_number_is_zero (left_num) && !ecma_number_is_zero (right_num)))
|
||||
{
|
||||
return left_num;
|
||||
}
|
||||
|
||||
return ecma_number_calc_remainder (left_num, right_num);
|
||||
} /* ecma_op_number_remainder */
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
||||
@ -1,35 +0,0 @@
|
||||
/* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ECMA_NUMBER_ARITHMETIC_H
|
||||
#define ECMA_NUMBER_ARITHMETIC_H
|
||||
|
||||
#include "ecma-globals.h"
|
||||
|
||||
/** \addtogroup ecma ECMA
|
||||
* @{
|
||||
*
|
||||
* \addtogroup numberarithmetic ECMA number arithmetic operations
|
||||
* @{
|
||||
*/
|
||||
|
||||
ecma_number_t ecma_op_number_remainder (ecma_number_t left_num, ecma_number_t right_num);
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* !ECMA_NUMBER_ARITHMETIC_H */
|
||||
@ -22,10 +22,12 @@
|
||||
#include "ecma-bigint.h"
|
||||
#include "ecma-builtin-helpers.h"
|
||||
#include "ecma-builtins.h"
|
||||
#include "ecma-conversion.h"
|
||||
#include "ecma-exceptions.h"
|
||||
#include "ecma-function-object.h"
|
||||
#include "ecma-gc.h"
|
||||
#include "ecma-globals.h"
|
||||
#include "ecma-helpers-number.h"
|
||||
#include "ecma-helpers.h"
|
||||
#include "ecma-iterator-object.h"
|
||||
#include "ecma-objects-general.h"
|
||||
|
||||
@ -335,6 +335,35 @@ lit_char_is_binary_digit (ecma_char_t c) /** code unit */
|
||||
} /* lit_char_is_binary_digit */
|
||||
#endif /* JERRY_ESNEXT */
|
||||
|
||||
/**
|
||||
* @return radix value
|
||||
*/
|
||||
uint8_t
|
||||
lit_char_to_radix (lit_utf8_byte_t c) /** code unit */
|
||||
{
|
||||
switch (LEXER_TO_ASCII_LOWERCASE (c))
|
||||
{
|
||||
case LIT_CHAR_LOWERCASE_X:
|
||||
{
|
||||
return 16;
|
||||
}
|
||||
#if JERRY_ESNEXT
|
||||
case LIT_CHAR_LOWERCASE_O:
|
||||
{
|
||||
return 8;
|
||||
}
|
||||
case LIT_CHAR_LOWERCASE_B:
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
#endif /* JERRY_ESNEXT */
|
||||
default:
|
||||
{
|
||||
return 10;
|
||||
}
|
||||
}
|
||||
} /* lit_char_to_radix */
|
||||
|
||||
/**
|
||||
* UnicodeEscape abstract method
|
||||
*
|
||||
@ -370,14 +399,9 @@ lit_char_hex_to_int (ecma_char_t c) /**< code unit, corresponding to
|
||||
{
|
||||
return (uint32_t) (c - LIT_CHAR_ASCII_DIGITS_BEGIN);
|
||||
}
|
||||
else if (c >= LIT_CHAR_ASCII_LOWERCASE_LETTERS_HEX_BEGIN && c <= LIT_CHAR_ASCII_LOWERCASE_LETTERS_HEX_END)
|
||||
{
|
||||
return (uint32_t) (c - LIT_CHAR_ASCII_LOWERCASE_LETTERS_HEX_BEGIN + 10);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (uint32_t) (c - LIT_CHAR_ASCII_UPPERCASE_LETTERS_HEX_BEGIN + 10);
|
||||
}
|
||||
|
||||
const uint32_t hex_offset = 10 - (LIT_CHAR_LOWERCASE_A % 32);
|
||||
return (c % 32) + hex_offset;
|
||||
} /* lit_char_hex_to_int */
|
||||
|
||||
/**
|
||||
|
||||
@ -229,6 +229,7 @@ bool lit_char_is_hex_digit (ecma_char_t c);
|
||||
#if JERRY_ESNEXT
|
||||
bool lit_char_is_binary_digit (ecma_char_t c);
|
||||
#endif /* JERRY_ESNEXT */
|
||||
uint8_t lit_char_to_radix (lit_utf8_byte_t c);
|
||||
void lit_char_unicode_escape (ecma_stringbuilder_t *builder_p, ecma_char_t c);
|
||||
uint32_t lit_char_hex_to_int (ecma_char_t c);
|
||||
size_t lit_code_point_to_cesu8_bytes (uint8_t *dst_p, lit_code_point_t code_point);
|
||||
|
||||
@ -2619,44 +2619,19 @@ lexer_construct_number_object (parser_context_t *context_p, /**< context */
|
||||
{
|
||||
#endif /* JERRY_BUILTIN_BIGINT */
|
||||
ecma_number_t num;
|
||||
uint32_t options = 0;
|
||||
|
||||
if (context_p->token.extra_value < LEXER_NUMBER_OCTAL)
|
||||
{
|
||||
#if JERRY_ESNEXT
|
||||
num = ecma_utf8_string_to_number (context_p->token.lit_location.char_p, length, ECMA_CONVERSION_ALLOW_UNDERSCORE);
|
||||
#else /* !JERRY_ESNEXT */
|
||||
num = ecma_utf8_string_to_number (context_p->token.lit_location.char_p, length, 0);
|
||||
options |= ECMA_CONVERSION_ALLOW_UNDERSCORE;
|
||||
#endif /* JERRY_ESNEXT */
|
||||
|
||||
if (context_p->token.extra_value == LEXER_NUMBER_OCTAL)
|
||||
{
|
||||
num = ecma_utf8_string_to_number_by_radix (context_p->token.lit_location.char_p, length, 8, options);
|
||||
}
|
||||
else
|
||||
{
|
||||
const uint8_t *src_p = context_p->token.lit_location.char_p;
|
||||
const uint8_t *src_end_p = src_p + length - 1;
|
||||
ecma_number_t multiplier = 8.0;
|
||||
|
||||
JERRY_ASSERT (src_p[0] == LIT_CHAR_0);
|
||||
|
||||
#if JERRY_ESNEXT
|
||||
if (context_p->token.extra_value == LEXER_NUMBER_BINARY)
|
||||
{
|
||||
src_p++;
|
||||
multiplier = 2.0;
|
||||
}
|
||||
else if (LEXER_TO_ASCII_LOWERCASE (src_p[1]) == LIT_CHAR_LOWERCASE_O)
|
||||
{
|
||||
src_p++;
|
||||
}
|
||||
#endif /* JERRY_ESNEXT */
|
||||
|
||||
num = 0;
|
||||
do
|
||||
{
|
||||
if (src_p[1] == LIT_CHAR_UNDERSCORE)
|
||||
{
|
||||
src_p++;
|
||||
}
|
||||
num = num * multiplier + (ecma_number_t) (*(++src_p) - LIT_CHAR_0);
|
||||
} while (src_p < src_end_p);
|
||||
num = ecma_utf8_string_to_number (context_p->token.lit_location.char_p, length, options);
|
||||
}
|
||||
|
||||
if (is_expr)
|
||||
|
||||
@ -18,7 +18,6 @@
|
||||
#include "ecma-conversion.h"
|
||||
#include "ecma-exceptions.h"
|
||||
#include "ecma-helpers.h"
|
||||
#include "ecma-number-arithmetic.h"
|
||||
#include "ecma-objects.h"
|
||||
|
||||
#include "jrt-libc-includes.h"
|
||||
@ -89,7 +88,21 @@ do_number_arithmetic (number_arithmetic_op op, /**< number arithmetic operation
|
||||
}
|
||||
case NUMBER_ARITHMETIC_REMAINDER:
|
||||
{
|
||||
result = ecma_op_number_remainder (left_number, right_number);
|
||||
if (ecma_number_is_nan (left_number) || ecma_number_is_nan (right_number)
|
||||
|| ecma_number_is_infinity (left_number) || ecma_number_is_zero (right_number))
|
||||
{
|
||||
result = ecma_number_make_nan ();
|
||||
break;
|
||||
}
|
||||
|
||||
if (ecma_number_is_infinity (right_number)
|
||||
|| (ecma_number_is_zero (left_number) && !ecma_number_is_zero (right_number)))
|
||||
{
|
||||
result = left_number;
|
||||
break;
|
||||
}
|
||||
|
||||
result = ecma_number_remainder (left_number, right_number);
|
||||
break;
|
||||
}
|
||||
#if JERRY_ESNEXT
|
||||
|
||||
@ -42,8 +42,8 @@ assert((-0.03125).toString(2) === "-0.00001");
|
||||
assert((-0.03125).toString(16) === "-0.08");
|
||||
assert((-0.0001).toString(4) === "-0.000000122031232023223013010030231")
|
||||
assert((-0).toString(16) === "0");
|
||||
assert((1e+73).toString(35) === "2nx1mg1l0w4ujlpt449c5qfrkkmtpgpsfsc2prlaqtnjbli2")
|
||||
assert((-1e+73).toString(35) === "-2nx1mg1l0w4ujlpt449c5qfrkkmtpgpsfsc2prlaqtnjbli2")
|
||||
assert((1e+73).toString(35) === "2nx1mg1l0w6b000000000000000000000000000000000000")
|
||||
assert((-1e+73).toString(35) === "-2nx1mg1l0w6b000000000000000000000000000000000000")
|
||||
assert((1).toString(undefined) === "1")
|
||||
|
||||
assert((123400).toString(2) === "11110001000001000");
|
||||
@ -90,7 +90,7 @@ assert ((-0x100000000000061).toString(16) === "-100000000000060");
|
||||
|
||||
assert((123400).toString(new Number(16)) === "1e208");
|
||||
|
||||
assert(65535.9.toString(3) === "10022220020.2200220022002200220022102110122000001102212");
|
||||
assert(65535.9.toString(3) === "10022220020.220022002200220022002201");
|
||||
|
||||
var digit_chars = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
|
||||
|
||||
@ -1175,7 +1175,7 @@
|
||||
|
||||
(function tc_15_07_04_02__001() {
|
||||
var a = Number(0.1);
|
||||
assert(a.toString(36) === "0.3llllllllllqsn8td1p464unmi");
|
||||
assert(a.toString(36) === "0.3lllllllllm");
|
||||
})();
|
||||
|
||||
(function tc_15_07_04_02__013() {
|
||||
|
||||
@ -20,6 +20,7 @@
|
||||
#include "ecma-conversion.h"
|
||||
#include "ecma-exceptions.h"
|
||||
#include "ecma-globals.h"
|
||||
#include "ecma-helpers-number.h"
|
||||
#include "ecma-helpers.h"
|
||||
#include "ecma-init-finalize.h"
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user