/* Copyright 2014 Samsung Electronics Co., Ltd. * Copyright 2015 University of Szeged. * * 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. */ /** \addtogroup ecma ECMA * @{ * * \addtogroup ecmahelpers Helpers for operations with ECMA data types * @{ */ #include "ecma-globals.h" #include "ecma-helpers.h" #if CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT32 JERRY_STATIC_ASSERT (sizeof (ecma_number_t) == sizeof (uint32_t)); /** * Packing sign, fraction and biased exponent to ecma-number * * @return ecma-number with specified sign, biased_exponent and fraction */ static ecma_number_t ecma_number_pack (bool sign, /**< sign */ uint32_t biased_exp, /**< biased exponent */ uint64_t fraction) /**< fraction */ { const uint32_t fraction_pos = 0; const uint32_t biased_exp_pos = fraction_pos + ECMA_NUMBER_FRACTION_WIDTH; const uint32_t sign_pos = biased_exp_pos + ECMA_NUMBER_BIASED_EXP_WIDTH; JERRY_ASSERT ((biased_exp & ~((1u << ECMA_NUMBER_BIASED_EXP_WIDTH) - 1)) == 0); JERRY_ASSERT ((fraction & ~((1ull << ECMA_NUMBER_FRACTION_WIDTH) - 1)) == 0); uint32_t packed_value = (((sign ? 1u : 0u) << sign_pos) | (biased_exp << biased_exp_pos) | (((uint32_t) fraction) << fraction_pos)); union { uint32_t u32_value; ecma_number_t float_value; } u; u.u32_value = packed_value; return u.float_value; } /* ecma_number_pack */ /** * Unpacking sign, fraction and biased exponent from ecma-number */ static void ecma_number_unpack (ecma_number_t num, /**< ecma-number */ bool *sign_p, /**< optional out: sign */ uint32_t *biased_exp_p, /**< optional out: biased exponent */ uint64_t *fraction_p) /**< optional out: fraction */ { const uint32_t fraction_pos = 0; const uint32_t biased_exp_pos = fraction_pos + ECMA_NUMBER_FRACTION_WIDTH; const uint32_t sign_pos = biased_exp_pos + ECMA_NUMBER_BIASED_EXP_WIDTH; union { uint32_t u32_value; ecma_number_t float_value; } u; u.float_value = num; uint32_t packed_value = u.u32_value; if (sign_p != NULL) { *sign_p = ((packed_value >> sign_pos) != 0); } if (biased_exp_p != NULL) { *biased_exp_p = (((packed_value) & ~(1u << sign_pos)) >> biased_exp_pos); } if (fraction_p != NULL) { *fraction_p = (packed_value & ((1u << ECMA_NUMBER_FRACTION_WIDTH) - 1)); } } /* ecma_number_unpack */ /** * Value used to calculate exponent from biased exponent * * See also: * IEEE-754 2008, 3.6, Table 3.5 */ const int32_t ecma_number_exponent_bias = 127; /** * Relative precision used in calculation with ecma-numbers */ const ecma_number_t ecma_number_relative_eps = 1.0e-10f; #elif CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64 JERRY_STATIC_ASSERT (sizeof (ecma_number_t) == sizeof (uint64_t)); /** * Packing sign, fraction and biased exponent to ecma-number * * @return ecma-number with specified sign, biased_exponent and fraction */ static ecma_number_t ecma_number_pack (bool sign, /**< sign */ uint32_t biased_exp, /**< biased exponent */ uint64_t fraction) /**< fraction */ { const uint32_t fraction_pos = 0; const uint32_t biased_exp_pos = fraction_pos + ECMA_NUMBER_FRACTION_WIDTH; const uint32_t sign_pos = biased_exp_pos + ECMA_NUMBER_BIASED_EXP_WIDTH; uint64_t packed_value = (((sign ? 1ull : 0ull) << sign_pos) | (((uint64_t) biased_exp) << biased_exp_pos) | (fraction << fraction_pos)); JERRY_ASSERT ((biased_exp & ~((1u << ECMA_NUMBER_BIASED_EXP_WIDTH) - 1)) == 0); JERRY_ASSERT ((fraction & ~((1ull << ECMA_NUMBER_FRACTION_WIDTH) - 1)) == 0); union { uint64_t u64_value; ecma_number_t float_value; } u; u.u64_value = packed_value; return u.float_value; } /* ecma_number_pack */ /** * Unpacking sign, fraction and biased exponent from ecma-number */ static void ecma_number_unpack (ecma_number_t num, /**< ecma-number */ bool *sign_p, /**< optional out: sign */ uint32_t *biased_exp_p, /**< optional out: biased exponent */ uint64_t *fraction_p) /**< optional out: fraction */ { const uint32_t fraction_pos = 0; const uint32_t biased_exp_pos = fraction_pos + ECMA_NUMBER_FRACTION_WIDTH; const uint32_t sign_pos = biased_exp_pos + ECMA_NUMBER_BIASED_EXP_WIDTH; union { uint64_t u64_value; ecma_number_t float_value; } u; u.float_value = num; uint64_t packed_value = u.u64_value; if (sign_p != NULL) { *sign_p = ((packed_value >> sign_pos) != 0); } if (biased_exp_p != NULL) { *biased_exp_p = (uint32_t) (((packed_value) & ~(1ull << sign_pos)) >> biased_exp_pos); } if (fraction_p != NULL) { *fraction_p = (packed_value & ((1ull << ECMA_NUMBER_FRACTION_WIDTH) - 1)); } } /* ecma_number_unpack */ /** * Value used to calculate exponent from biased exponent * * See also: * IEEE-754 2008, 3.6, Table 3.5 */ const int32_t ecma_number_exponent_bias = 1023; /** * Relative precision used in calculation with ecma-numbers */ const ecma_number_t ecma_number_relative_eps = 1.0e-16; #endif /* CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64 */ /** * Get fraction of number * * @return normalized fraction field of number */ static uint64_t ecma_number_get_fraction_field (ecma_number_t num) /**< ecma-number */ { uint64_t fraction; ecma_number_unpack (num, NULL, NULL, &fraction); return fraction; } /* ecma_number_get_fraction_field */ /** * Get exponent of number * * @return exponent corresponding to normalized fraction of number */ static uint32_t ecma_number_get_biased_exponent_field (ecma_number_t num) /**< ecma-number */ { uint32_t biased_exp; ecma_number_unpack (num, NULL, &biased_exp, NULL); return biased_exp; } /* ecma_number_get_biased_exponent_field */ /** * Get sign bit of number * * @return 0 or 1 - value of sign bit */ static uint32_t ecma_number_get_sign_field (ecma_number_t num) /**< ecma-number */ { bool sign; ecma_number_unpack (num, &sign, NULL, NULL); return sign; } /* ecma_number_get_sign_field */ /** * Check if ecma-number is NaN * * @return true - if biased exponent is filled with 1 bits and fraction is filled with anything but not all zero bits, * false - otherwise */ bool ecma_number_is_nan (ecma_number_t num) /**< ecma-number */ { bool is_nan = (num != num); #ifndef JERRY_NDEBUG uint32_t biased_exp = ecma_number_get_biased_exponent_field (num); uint64_t fraction = ecma_number_get_fraction_field (num); /* IEEE-754 2008, 3.4, a */ bool is_nan_ieee754 = ((biased_exp == (1u << ECMA_NUMBER_BIASED_EXP_WIDTH) - 1) && (fraction != 0)); JERRY_ASSERT (is_nan == is_nan_ieee754); #endif /* !JERRY_NDEBUG */ return is_nan; } /* ecma_number_is_nan */ /** * Make a NaN. * * @return NaN value */ ecma_number_t ecma_number_make_nan (void) { return ecma_number_pack (false, (1u << ECMA_NUMBER_BIASED_EXP_WIDTH) - 1u, 1u); } /* ecma_number_make_nan */ /** * Make an Infinity. * * @return if !sign - +Infinity value, * else - -Infinity value. */ ecma_number_t ecma_number_make_infinity (bool sign) /**< true - for negative Infinity, false - for positive Infinity */ { return ecma_number_pack (sign, (1u << ECMA_NUMBER_BIASED_EXP_WIDTH) - 1u, 0u); } /* ecma_number_make_infinity */ /** * Check if ecma-number is negative * * @return true - if sign bit of ecma-number is set * false - otherwise */ bool ecma_number_is_negative (ecma_number_t num) /**< ecma-number */ { JERRY_ASSERT (!ecma_number_is_nan (num)); /* IEEE-754 2008, 3.4 */ return (ecma_number_get_sign_field (num) != 0); } /* ecma_number_is_negative */ /** * Check if ecma-number is zero * * @return true - if fraction is zero and biased exponent is zero, * false - otherwise */ bool ecma_number_is_zero (ecma_number_t num) /**< ecma-number */ { JERRY_ASSERT (!ecma_number_is_nan (num)); bool is_zero = (num == ECMA_NUMBER_ZERO); #ifndef JERRY_NDEBUG /* IEEE-754 2008, 3.4, e */ bool is_zero_ieee754 = (ecma_number_get_fraction_field (num) == 0 && ecma_number_get_biased_exponent_field (num) == 0); JERRY_ASSERT (is_zero == is_zero_ieee754); #endif /* !JERRY_NDEBUG */ return is_zero; } /* ecma_number_is_zero */ /** * Check if number is infinity * * @return true - if biased exponent is filled with 1 bits and * fraction is filled with zero bits, * false - otherwise. */ bool ecma_number_is_infinity (ecma_number_t num) /**< ecma-number */ { JERRY_ASSERT (!ecma_number_is_nan (num)); uint32_t biased_exp = ecma_number_get_biased_exponent_field (num); uint64_t fraction = ecma_number_get_fraction_field (num); /* IEEE-754 2008, 3.4, b */ return ((biased_exp == (1u << ECMA_NUMBER_BIASED_EXP_WIDTH) - 1) && (fraction == 0)); } /* ecma_number_is_infinity */ /** * Get fraction and exponent of the number * * @return shift of dot in the fraction */ int32_t ecma_number_get_fraction_and_exponent (ecma_number_t num, /**< ecma-number */ uint64_t *out_fraction_p, /**< out: fraction of the number */ int32_t *out_exponent_p) /**< out: exponent of the number */ { JERRY_ASSERT (!ecma_number_is_nan (num)); uint32_t biased_exp = ecma_number_get_biased_exponent_field (num); uint64_t fraction = ecma_number_get_fraction_field (num); int32_t exponent; if (unlikely (biased_exp == 0)) { /* IEEE-754 2008, 3.4, d */ if (ecma_number_is_zero (num)) { exponent = -ecma_number_exponent_bias; } else { exponent = 1 - ecma_number_exponent_bias; while (!(fraction & (1ull << ECMA_NUMBER_FRACTION_WIDTH))) { JERRY_ASSERT (fraction != 0); fraction <<= 1; exponent--; } } } else if (ecma_number_is_infinity (num)) { /* The fraction and exponent should round to infinity */ exponent = (int32_t) biased_exp - ecma_number_exponent_bias; JERRY_ASSERT ((fraction & (1ull << ECMA_NUMBER_FRACTION_WIDTH)) == 0); fraction |= 1ull << ECMA_NUMBER_FRACTION_WIDTH; } else { /* IEEE-754 2008, 3.4, c */ 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 & (1ull << ECMA_NUMBER_FRACTION_WIDTH)) == 0); fraction |= 1ull << ECMA_NUMBER_FRACTION_WIDTH; } *out_fraction_p = fraction; *out_exponent_p = exponent; return ECMA_NUMBER_FRACTION_WIDTH; } /* ecma_number_get_fraction_and_exponent */ /** * Make normalised positive Number from given fraction and exponent * * @return ecma-number */ ecma_number_t ecma_number_make_normal_positive_from_fraction_and_exponent (uint64_t fraction, /**< fraction */ int32_t exponent) /**< exponent */ { 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); return ecma_number_pack (false, biased_exp, fraction & ~(1ull << ECMA_NUMBER_FRACTION_WIDTH)); } /* 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 */ { /* 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); return ecma_number_pack (sign, biased_exp, mantissa); } /* ecma_number_make_from_sign_mantissa_and_exponent */ /** * Get previous representable ecma-number * * @return maximum ecma-number that is less compared to passed argument */ ecma_number_t ecma_number_get_prev (ecma_number_t num) /**< ecma-number */ { JERRY_ASSERT (!ecma_number_is_nan (num)); JERRY_ASSERT (!ecma_number_is_zero (num)); if (ecma_number_is_negative (num)) { return ecma_number_negate (ecma_number_get_next (num)); } uint32_t biased_exp = ecma_number_get_biased_exponent_field (num); uint64_t fraction = ecma_number_get_fraction_field (num); if (fraction == 0 && biased_exp != 0) { fraction = (1ull << ECMA_NUMBER_FRACTION_WIDTH) - 1; biased_exp--; } else { fraction--; } return ecma_number_pack (false, biased_exp, fraction); } /* ecma_number_get_prev */ /** * Get next representable ecma-number * * @return minimum ecma-number that is greater compared to passed argument */ ecma_number_t ecma_number_get_next (ecma_number_t num) /**< ecma-number */ { JERRY_ASSERT (!ecma_number_is_nan (num)); JERRY_ASSERT (!ecma_number_is_infinity (num)); if (ecma_number_is_negative (num)) { return ecma_number_negate (ecma_number_get_prev (num)); } uint32_t biased_exp = ecma_number_get_biased_exponent_field (num); uint64_t fraction = ecma_number_get_fraction_field (num); fraction |= (1ull << ECMA_NUMBER_FRACTION_WIDTH); fraction++; if ((fraction & (1ull << ECMA_NUMBER_FRACTION_WIDTH)) == 0) { fraction >>= 1; biased_exp++; } JERRY_ASSERT (fraction & (1ull << ECMA_NUMBER_FRACTION_WIDTH)); fraction &= ~(1ull << ECMA_NUMBER_FRACTION_WIDTH); return ecma_number_pack (false, biased_exp, fraction); } /* ecma_number_get_next */ /** * Negate ecma-number * * @return negated number */ ecma_number_t ecma_number_negate (ecma_number_t num) /**< ecma-number */ { ecma_number_t negated = -num; #ifndef JERRY_NDEBUG bool sign; uint32_t biased_exp; uint64_t fraction; ecma_number_unpack (num, &sign, &biased_exp, &fraction); sign = !sign; ecma_number_t negated_ieee754 = ecma_number_pack (sign, biased_exp, fraction); JERRY_ASSERT (negated == negated_ieee754 || (ecma_number_is_nan (negated) && ecma_number_is_nan (negated_ieee754))); #endif /* !JERRY_NDEBUG */ return negated; } /* ecma_number_negate */ /** * Truncate fractional part of the number * * @return integer part of the number */ ecma_number_t ecma_number_trunc (ecma_number_t num) /**< ecma-number */ { uint64_t fraction; int32_t exponent; const int32_t dot_shift = ecma_number_get_fraction_and_exponent (num, &fraction, &exponent); const bool sign = ecma_number_is_negative (num); if (exponent < 0) { return 0; } else if (exponent < dot_shift) { fraction &= ~((1ull << (dot_shift - exponent)) - 1); ecma_number_t tmp = ecma_number_make_normal_positive_from_fraction_and_exponent (fraction, exponent); if (sign) { return ecma_number_negate (tmp); } else { return tmp; } } else { return num; } } /* ecma_number_trunc */ /** * Calculate remainder of division of two numbers, * as specified in ECMA-262 v5, 11.5.3, item 6. * * Note: * operands shouldn't contain NaN, Infinity, or zero. * * @return number - calculated remainder. */ ecma_number_t ecma_number_calc_remainder (ecma_number_t left_num, /**< left operand */ ecma_number_t right_num) /**< right operand */ { ecma_number_t n = left_num, d = right_num; JERRY_ASSERT (!ecma_number_is_nan (n) && !ecma_number_is_zero (n) && !ecma_number_is_infinity (n)); JERRY_ASSERT (!ecma_number_is_nan (d) && !ecma_number_is_zero (d) && !ecma_number_is_infinity (d)); ecma_number_t q = ecma_number_trunc (ecma_number_divide (n, d)); ecma_number_t r = ecma_number_substract (n, ecma_number_multiply (d, q)); if (ecma_number_is_zero (r) && ecma_number_is_negative (n)) { r = ecma_number_negate (r); } return r; } /* ecma_number_calc_remainder */ /** * ECMA-number addition. * * @return number - result of addition. */ ecma_number_t ecma_number_add (ecma_number_t left_num, /**< left operand */ ecma_number_t right_num) /**< right operand */ { return left_num + right_num; } /* ecma_number_add */ /** * ECMA-number substraction. * * @return number - result of substraction. */ ecma_number_t ecma_number_substract (ecma_number_t left_num, /**< left operand */ ecma_number_t right_num) /**< right operand */ { return ecma_number_add (left_num, ecma_number_negate (right_num)); } /* ecma_number_substract */ /** * ECMA-number multiplication. * * @return number - result of multiplication. */ ecma_number_t ecma_number_multiply (ecma_number_t left_num, /**< left operand */ ecma_number_t right_num) /**< right operand */ { return left_num * right_num; } /* ecma_number_multiply */ /** * ECMA-number division. * * @return number - result of division. */ ecma_number_t ecma_number_divide (ecma_number_t left_num, /**< left operand */ ecma_number_t right_num) /**< right operand */ { return left_num / right_num; } /* ecma_number_divide */ /** * Helper for calculating absolute value * * Warning: * argument should be valid number * * @return absolute value of the argument */ ecma_number_t ecma_number_abs (ecma_number_t num) /**< valid number */ { JERRY_ASSERT (!ecma_number_is_nan (num)); if (num < 0) { return ecma_number_negate (num); } else { return num; } } /* ecma_number_abs */ /** * Helper for calculating square root using Newton's method. * * @return square root of specified number */ ecma_number_t ecma_number_sqrt (ecma_number_t num) /**< valid finite positive number */ { JERRY_ASSERT (!ecma_number_is_nan (num)); JERRY_ASSERT (!ecma_number_is_infinity (num)); JERRY_ASSERT (!ecma_number_is_negative (num)); ecma_number_t x = ECMA_NUMBER_ONE; ecma_number_t diff = ecma_number_make_infinity (false); while (ecma_number_divide (diff, x) > ecma_number_relative_eps) { ecma_number_t x_next = ecma_number_multiply (ECMA_NUMBER_HALF, (ecma_number_add (x, ecma_number_divide (num, x)))); diff = ecma_number_substract (x, x_next); if (diff < 0) { diff = ecma_number_negate (diff); } x = x_next; } return x; } /* ecma_number_sqrt */ /** * Helper for calculating natural logarithm. * * @return natural logarithm of specified number */ ecma_number_t ecma_number_ln (ecma_number_t num) /**< valid finite positive number */ { JERRY_ASSERT (!ecma_number_is_nan (num)); JERRY_ASSERT (!ecma_number_is_infinity (num)); JERRY_ASSERT (!ecma_number_is_negative (num)); if (num == ECMA_NUMBER_ONE) { return ECMA_NUMBER_ZERO; } /* Taylor series of ln (1 + x) around x = 0 is x - x^2/2 + x^3/3 - x^4/4 + ... */ ecma_number_t x = num; ecma_number_t multiplier = ECMA_NUMBER_ONE; while (ecma_number_abs (ecma_number_substract (x, ECMA_NUMBER_ONE)) > ECMA_NUMBER_HALF) { x = ecma_number_sqrt (x); multiplier = ecma_number_multiply (multiplier, ECMA_NUMBER_TWO); } x = ecma_number_substract (x, ECMA_NUMBER_ONE); ecma_number_t sum = ECMA_NUMBER_ZERO; ecma_number_t next_power = x; ecma_number_t next_divisor = ECMA_NUMBER_ONE; ecma_number_t diff; do { ecma_number_t next_sum = ecma_number_add (sum, ecma_number_divide (next_power, next_divisor)); next_divisor = ecma_number_add (next_divisor, ECMA_NUMBER_ONE); next_power = ecma_number_multiply (next_power, x); next_power = ecma_number_negate (next_power); diff = ecma_number_abs (ecma_number_substract (sum, next_sum)); sum = next_sum; } while (ecma_number_abs (ecma_number_divide (diff, sum)) > ecma_number_relative_eps); sum = ecma_number_multiply (sum, multiplier); return sum; } /* ecma_number_ln */ /** * Helper for calculating exponent of a number * * @return exponent of specified number */ ecma_number_t ecma_number_exp (ecma_number_t num) /**< valid finite number */ { JERRY_ASSERT (!ecma_number_is_nan (num)); JERRY_ASSERT (!ecma_number_is_infinity (num)); bool invert = false; ecma_number_t pow_e; if (ecma_number_is_negative (num)) { invert = true; pow_e = ecma_number_negate (num); } else { pow_e = num; } /* Taylor series of e^x is 1 + x/1! + x^2/2! + x^3/3! + ... + x^n/n! + ... */ ecma_number_t sum = ECMA_NUMBER_ONE; ecma_number_t next_addendum = ecma_number_divide (pow_e, ECMA_NUMBER_ONE); ecma_number_t next_factorial_factor = ECMA_NUMBER_ONE; ecma_number_t diff = ecma_number_make_infinity (false); while (ecma_number_divide (diff, sum) > ecma_number_relative_eps) { ecma_number_t next_sum = ecma_number_add (sum, next_addendum); next_factorial_factor = ecma_number_add (next_factorial_factor, ECMA_NUMBER_ONE); next_addendum = ecma_number_multiply (next_addendum, pow_e); next_addendum = ecma_number_divide (next_addendum, next_factorial_factor); diff = ecma_number_substract (sum, next_sum); if (diff < 0) { diff = ecma_number_negate (diff); } sum = next_sum; } if (invert) { sum = ecma_number_divide (ECMA_NUMBER_ONE, sum); } return sum; } /* ecma_number_exp */ /** * @} * @} */