Implement printing in the specified radix for Number.prototype.toString().
JerryScript-DCO-1.0-Signed-off-by: Dániel Bátyai dbatyai.u-szeged@partner.samsung.com
This commit is contained in:
@@ -579,6 +579,30 @@ typedef float ecma_number_t;
|
||||
* 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 CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64
|
||||
/**
|
||||
* Description of an ecma-number
|
||||
@@ -590,6 +614,30 @@ typedef double ecma_number_t;
|
||||
* Maximum number of significant digits that ecma-number can store
|
||||
*/
|
||||
#define ECMA_NUMBER_MAX_DIGITS (18)
|
||||
|
||||
/**
|
||||
* 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)
|
||||
#endif /* CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64 */
|
||||
|
||||
/**
|
||||
|
||||
@@ -27,30 +27,6 @@
|
||||
#if CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT32
|
||||
JERRY_STATIC_ASSERT (sizeof (ecma_number_t) == sizeof (uint32_t));
|
||||
|
||||
/**
|
||||
* 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)
|
||||
|
||||
/**
|
||||
* Packing sign, fraction and biased exponent to ecma-number
|
||||
*
|
||||
@@ -137,30 +113,6 @@ 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));
|
||||
|
||||
/**
|
||||
* 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)
|
||||
|
||||
/**
|
||||
* Packing sign, fraction and biased exponent to ecma-number
|
||||
*
|
||||
|
||||
@@ -24,7 +24,9 @@
|
||||
#include "ecma-objects.h"
|
||||
#include "ecma-string-object.h"
|
||||
#include "ecma-try-catch-macro.h"
|
||||
#include "fdlibm-math.h"
|
||||
#include "jrt.h"
|
||||
#include "jrt-libc-includes.h"
|
||||
|
||||
#ifndef CONFIG_ECMA_COMPACT_PROFILE_DISABLE_NUMBER_BUILTIN
|
||||
|
||||
@@ -118,14 +120,220 @@ ecma_builtin_number_prototype_object_to_string (ecma_value_t this_arg, /**< this
|
||||
return ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE));
|
||||
}
|
||||
|
||||
if (arguments_list_len == 0)
|
||||
if (arguments_list_len == 0
|
||||
|| ecma_number_is_nan (this_arg_number)
|
||||
|| ecma_number_is_infinity (this_arg_number)
|
||||
|| ecma_number_is_zero (this_arg_number))
|
||||
{
|
||||
ecma_string_t *ret_str_p = ecma_new_ecma_string_from_number (this_arg_number);
|
||||
|
||||
return ecma_make_normal_completion_value (ecma_make_string_value (ret_str_p));
|
||||
}
|
||||
else
|
||||
{
|
||||
ECMA_BUILTIN_CP_UNIMPLEMENTED (arguments_list_p);
|
||||
const lit_utf8_byte_t digit_chars[36] =
|
||||
{
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
|
||||
'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
|
||||
'u', 'v', 'w', 'x', 'y', 'z'
|
||||
};
|
||||
|
||||
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
|
||||
ECMA_OP_TO_NUMBER_TRY_CATCH (arg_num, arguments_list_p[0], ret_value);
|
||||
|
||||
uint32_t radix = ecma_number_to_uint32 (arg_num);
|
||||
|
||||
if (radix < 2 || radix > 36)
|
||||
{
|
||||
ret_value = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_RANGE));
|
||||
}
|
||||
else if (radix == 10)
|
||||
{
|
||||
ecma_string_t *ret_str_p = ecma_new_ecma_string_from_number (this_arg_number);
|
||||
|
||||
ret_value = ecma_make_normal_completion_value (ecma_make_string_value (ret_str_p));
|
||||
}
|
||||
else
|
||||
{
|
||||
uint64_t digits;
|
||||
int32_t num_digits;
|
||||
int32_t exponent;
|
||||
bool is_negative = false;
|
||||
|
||||
if (ecma_number_is_negative (this_arg_number))
|
||||
{
|
||||
this_arg_number = -this_arg_number;
|
||||
is_negative = true;
|
||||
}
|
||||
|
||||
ecma_number_to_decimal (this_arg_number, &digits, &num_digits, &exponent);
|
||||
|
||||
exponent = exponent - num_digits;
|
||||
bool is_scale_negative = false;
|
||||
|
||||
/* Calculate the scale of the number in the specified radix. */
|
||||
int scale = (int) -floor ((log (10) / log (radix)) * exponent);
|
||||
|
||||
int buff_size;
|
||||
|
||||
if (is_scale_negative)
|
||||
{
|
||||
buff_size = (int) floor ((log (this_arg_number) / log (10))) + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
buff_size = scale + ECMA_NUMBER_FRACTION_WIDTH + 2;
|
||||
}
|
||||
|
||||
if (is_negative)
|
||||
{
|
||||
buff_size++;
|
||||
}
|
||||
|
||||
if (scale < 0)
|
||||
{
|
||||
is_scale_negative = true;
|
||||
scale = -scale;
|
||||
}
|
||||
|
||||
/* Normalize the number, so that it is as close to 0 exponent as possible. */
|
||||
for (int i = 0; i < scale; i++)
|
||||
{
|
||||
if (is_scale_negative)
|
||||
{
|
||||
this_arg_number /= (ecma_number_t) radix;
|
||||
}
|
||||
else
|
||||
{
|
||||
this_arg_number *= (ecma_number_t) radix;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t whole = (uint64_t) this_arg_number;
|
||||
ecma_number_t fraction = this_arg_number - (ecma_number_t) whole;
|
||||
|
||||
MEM_DEFINE_LOCAL_ARRAY (buff, buff_size, lit_utf8_byte_t);
|
||||
int buff_index = 0;
|
||||
|
||||
/* Calculate digits for whole part. */
|
||||
while (whole > 0)
|
||||
{
|
||||
buff[buff_index++] = (lit_utf8_byte_t) (whole % radix);
|
||||
whole /= radix;
|
||||
}
|
||||
|
||||
/* Calculate where we have to put the radix point. */
|
||||
int point = is_scale_negative ? buff_index + scale : buff_index - scale;
|
||||
|
||||
/* Reverse the digits, since they are backwards. */
|
||||
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;
|
||||
}
|
||||
|
||||
bool should_round = false;
|
||||
/* Calculate digits for fractional part. */
|
||||
for (int iter_count = 0;
|
||||
iter_count < ECMA_NUMBER_FRACTION_WIDTH && (fraction != 0 || is_scale_negative);
|
||||
iter_count++)
|
||||
{
|
||||
fraction *= (ecma_number_t) radix;
|
||||
lit_utf8_byte_t digit = (lit_utf8_byte_t) floor (fraction);
|
||||
|
||||
buff[buff_index++] = digit;
|
||||
fraction -= (ecma_number_t) floor (fraction);
|
||||
|
||||
if (iter_count == scale && is_scale_negative)
|
||||
{
|
||||
/*
|
||||
* When scale is negative, that means the original number did not have a fractional part,
|
||||
* but by normalizing it, we introduced one. In this case, when the iteration count reaches
|
||||
* the scale, we already have the number, but it may be incorrect, so we calculate
|
||||
* one extra digit that we round off just to make sure.
|
||||
*/
|
||||
should_round = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (should_round)
|
||||
{
|
||||
/* Round off last digit. */
|
||||
if (buff[buff_index - 1] > radix / 2)
|
||||
{
|
||||
buff[buff_index - 2]++;
|
||||
}
|
||||
|
||||
buff_index--;
|
||||
|
||||
/* Propagate carry. */
|
||||
for (int i = buff_index - 1; i > 0 && buff[i] >= radix; i--)
|
||||
{
|
||||
buff[i] = (lit_utf8_byte_t) (buff[i] - radix);
|
||||
buff[i - 1]++;
|
||||
}
|
||||
|
||||
/* Carry propagated over the whole number, need to add a leading digit. */
|
||||
if (buff[0] >= radix)
|
||||
{
|
||||
memmove (buff + 1, buff, (size_t) buff_index);
|
||||
buff_index++;
|
||||
buff[0] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Remove trailing zeros from fraction. */
|
||||
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)
|
||||
{
|
||||
memmove (buff - point + 1, buff, (size_t) buff_index);
|
||||
buff_index += -point + 1;
|
||||
|
||||
for (int i = 0; i < -point + 1; i++)
|
||||
{
|
||||
buff[i] = 0;
|
||||
}
|
||||
|
||||
point = 1;
|
||||
}
|
||||
|
||||
/* Convert digits to characters. */
|
||||
for (int i = 0; i < buff_index; i++)
|
||||
{
|
||||
buff[i] = digit_chars[buff[i]];
|
||||
}
|
||||
|
||||
/* Place radix point to the required position. */
|
||||
if (point < buff_index)
|
||||
{
|
||||
memmove (buff + point + 1, buff + point, (size_t) buff_index);
|
||||
buff[point] = '.';
|
||||
buff_index++;
|
||||
}
|
||||
|
||||
/* Add negative sign if necessary. */
|
||||
if (is_negative)
|
||||
{
|
||||
memmove (buff + 1, buff, (size_t) buff_index);
|
||||
buff_index++;
|
||||
buff[0] = '-';
|
||||
}
|
||||
|
||||
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_normal_completion_value (ecma_make_string_value (str_p));
|
||||
MEM_FINALIZE_LOCAL_ARRAY (buff);
|
||||
}
|
||||
ECMA_OP_TO_NUMBER_FINALIZE (arg_num);
|
||||
return ret_value;
|
||||
}
|
||||
} /* ecma_builtin_number_prototype_object_to_string */
|
||||
|
||||
|
||||
Reference in New Issue
Block a user