Skip to content

Commit 5e0a355

Browse files
committed
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
1 parent c12914c commit 5e0a355

File tree

4 files changed

+378
-50
lines changed

4 files changed

+378
-50
lines changed

jerry-core/ecma/base/ecma-globals.h

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,30 @@ typedef float ecma_number_t;
579579
* Maximum number of significant digits that ecma-number can store
580580
*/
581581
#define ECMA_NUMBER_MAX_DIGITS (9)
582+
583+
/**
584+
* Width of sign field
585+
*
586+
* See also:
587+
* IEEE-754 2008, 3.6, Table 3.5
588+
*/
589+
#define ECMA_NUMBER_SIGN_WIDTH (1)
590+
591+
/**
592+
* Width of biased exponent field
593+
*
594+
* See also:
595+
* IEEE-754 2008, 3.6, Table 3.5
596+
*/
597+
#define ECMA_NUMBER_BIASED_EXP_WIDTH (8)
598+
599+
/**
600+
* Width of fraction field
601+
*
602+
* See also:
603+
* IEEE-754 2008, 3.6, Table 3.5
604+
*/
605+
#define ECMA_NUMBER_FRACTION_WIDTH (23)
582606
#elif CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64
583607
/**
584608
* Description of an ecma-number
@@ -590,6 +614,30 @@ typedef double ecma_number_t;
590614
* Maximum number of significant digits that ecma-number can store
591615
*/
592616
#define ECMA_NUMBER_MAX_DIGITS (18)
617+
618+
/**
619+
* Width of sign field
620+
*
621+
* See also:
622+
* IEEE-754 2008, 3.6, Table 3.5
623+
*/
624+
#define ECMA_NUMBER_SIGN_WIDTH (1)
625+
626+
/**
627+
* Width of biased exponent field
628+
*
629+
* See also:
630+
* IEEE-754 2008, 3.6, Table 3.5
631+
*/
632+
#define ECMA_NUMBER_BIASED_EXP_WIDTH (11)
633+
634+
/**
635+
* Width of fraction field
636+
*
637+
* See also:
638+
* IEEE-754 2008, 3.6, Table 3.5
639+
*/
640+
#define ECMA_NUMBER_FRACTION_WIDTH (52)
593641
#endif /* CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64 */
594642

595643
/**

jerry-core/ecma/base/ecma-helpers-number.cpp

Lines changed: 0 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -27,30 +27,6 @@
2727
#if CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT32
2828
JERRY_STATIC_ASSERT (sizeof (ecma_number_t) == sizeof (uint32_t));
2929

30-
/**
31-
* Width of sign field
32-
*
33-
* See also:
34-
* IEEE-754 2008, 3.6, Table 3.5
35-
*/
36-
#define ECMA_NUMBER_SIGN_WIDTH (1)
37-
38-
/**
39-
* Width of biased exponent field
40-
*
41-
* See also:
42-
* IEEE-754 2008, 3.6, Table 3.5
43-
*/
44-
#define ECMA_NUMBER_BIASED_EXP_WIDTH (8)
45-
46-
/**
47-
* Width of fraction field
48-
*
49-
* See also:
50-
* IEEE-754 2008, 3.6, Table 3.5
51-
*/
52-
#define ECMA_NUMBER_FRACTION_WIDTH (23)
53-
5430
/**
5531
* Packing sign, fraction and biased exponent to ecma-number
5632
*
@@ -137,30 +113,6 @@ const ecma_number_t ecma_number_relative_eps = 1.0e-10f;
137113
#elif CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64
138114
JERRY_STATIC_ASSERT (sizeof (ecma_number_t) == sizeof (uint64_t));
139115

140-
/**
141-
* Width of sign field
142-
*
143-
* See also:
144-
* IEEE-754 2008, 3.6, Table 3.5
145-
*/
146-
#define ECMA_NUMBER_SIGN_WIDTH (1)
147-
148-
/**
149-
* Width of biased exponent field
150-
*
151-
* See also:
152-
* IEEE-754 2008, 3.6, Table 3.5
153-
*/
154-
#define ECMA_NUMBER_BIASED_EXP_WIDTH (11)
155-
156-
/**
157-
* Width of fraction field
158-
*
159-
* See also:
160-
* IEEE-754 2008, 3.6, Table 3.5
161-
*/
162-
#define ECMA_NUMBER_FRACTION_WIDTH (52)
163-
164116
/**
165117
* Packing sign, fraction and biased exponent to ecma-number
166118
*

jerry-core/ecma/builtin-objects/ecma-builtin-number-prototype.cpp

Lines changed: 210 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@
2424
#include "ecma-objects.h"
2525
#include "ecma-string-object.h"
2626
#include "ecma-try-catch-macro.h"
27+
#include "fdlibm-math.h"
2728
#include "jrt.h"
29+
#include "jrt-libc-includes.h"
2830

2931
#ifndef CONFIG_ECMA_COMPACT_PROFILE_DISABLE_NUMBER_BUILTIN
3032

@@ -118,14 +120,220 @@ ecma_builtin_number_prototype_object_to_string (ecma_value_t this_arg, /**< this
118120
return ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE));
119121
}
120122

121-
if (arguments_list_len == 0)
123+
if (arguments_list_len == 0
124+
|| ecma_number_is_nan (this_arg_number)
125+
|| ecma_number_is_infinity (this_arg_number)
126+
|| ecma_number_is_zero (this_arg_number))
122127
{
123128
ecma_string_t *ret_str_p = ecma_new_ecma_string_from_number (this_arg_number);
124129

125130
return ecma_make_normal_completion_value (ecma_make_string_value (ret_str_p));
126131
}
132+
else
127133
{
128-
ECMA_BUILTIN_CP_UNIMPLEMENTED (arguments_list_p);
134+
const lit_utf8_byte_t digit_chars[36] =
135+
{
136+
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
137+
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
138+
'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
139+
'u', 'v', 'w', 'x', 'y', 'z'
140+
};
141+
142+
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
143+
ECMA_OP_TO_NUMBER_TRY_CATCH (arg_num, arguments_list_p[0], ret_value);
144+
145+
uint32_t radix = ecma_number_to_uint32 (arg_num);
146+
147+
if (radix < 2 || radix > 36)
148+
{
149+
ret_value = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_RANGE));
150+
}
151+
else if (radix == 10)
152+
{
153+
ecma_string_t *ret_str_p = ecma_new_ecma_string_from_number (this_arg_number);
154+
155+
ret_value = ecma_make_normal_completion_value (ecma_make_string_value (ret_str_p));
156+
}
157+
else
158+
{
159+
uint64_t digits;
160+
int32_t num_digits;
161+
int32_t exponent;
162+
bool is_negative = false;
163+
164+
if (ecma_number_is_negative (this_arg_number))
165+
{
166+
this_arg_number = -this_arg_number;
167+
is_negative = true;
168+
}
169+
170+
ecma_number_to_decimal (this_arg_number, &digits, &num_digits, &exponent);
171+
172+
exponent = exponent - num_digits;
173+
bool is_scale_negative = false;
174+
175+
/* Calculate the scale of the number in the specified radix. */
176+
int scale = (int) -floor ((log (10) / log (radix)) * exponent);
177+
178+
int buff_size;
179+
180+
if (is_scale_negative)
181+
{
182+
buff_size = (int) floor ((log (this_arg_number) / log (10))) + 1;
183+
}
184+
else
185+
{
186+
buff_size = scale + ECMA_NUMBER_FRACTION_WIDTH + 2;
187+
}
188+
189+
if (is_negative)
190+
{
191+
buff_size++;
192+
}
193+
194+
if (scale < 0)
195+
{
196+
is_scale_negative = true;
197+
scale = -scale;
198+
}
199+
200+
/* Normalize the number, so that it is as close to 0 exponent as possible. */
201+
for (int i = 0; i < scale; i++)
202+
{
203+
if (is_scale_negative)
204+
{
205+
this_arg_number /= (ecma_number_t) radix;
206+
}
207+
else
208+
{
209+
this_arg_number *= (ecma_number_t) radix;
210+
}
211+
}
212+
213+
uint64_t whole = (uint64_t) this_arg_number;
214+
ecma_number_t fraction = this_arg_number - (ecma_number_t) whole;
215+
216+
MEM_DEFINE_LOCAL_ARRAY (buff, buff_size, lit_utf8_byte_t);
217+
int buff_index = 0;
218+
219+
/* Calculate digits for whole part. */
220+
while (whole > 0)
221+
{
222+
buff[buff_index++] = (lit_utf8_byte_t) (whole % radix);
223+
whole /= radix;
224+
}
225+
226+
/* Calculate where we have to put the radix point. */
227+
int point = is_scale_negative ? buff_index + scale : buff_index - scale;
228+
229+
/* Reverse the digits, since they are backwards. */
230+
for (int i = 0; i < buff_index / 2; i++)
231+
{
232+
lit_utf8_byte_t swap = buff[i];
233+
buff[i] = buff[buff_index - i - 1];
234+
buff[buff_index - i - 1] = swap;
235+
}
236+
237+
bool should_round = false;
238+
/* Calculate digits for fractional part. */
239+
for (int iter_count = 0;
240+
iter_count < ECMA_NUMBER_FRACTION_WIDTH && (fraction != 0 || is_scale_negative);
241+
iter_count++)
242+
{
243+
fraction *= (ecma_number_t) radix;
244+
lit_utf8_byte_t digit = (lit_utf8_byte_t) floor (fraction);
245+
246+
buff[buff_index++] = digit;
247+
fraction -= (ecma_number_t) floor (fraction);
248+
249+
if (iter_count == scale && is_scale_negative)
250+
{
251+
/*
252+
* When scale is negative, that means the original number did not have a fractional part,
253+
* but by normalizing it, we introduced one. In this case, when the iteration count reaches
254+
* the scale, we already have the number, but it may be incorrect, so we calculate
255+
* one extra digit that we round off just to make sure.
256+
*/
257+
should_round = true;
258+
break;
259+
}
260+
}
261+
262+
if (should_round)
263+
{
264+
/* Round off last digit. */
265+
if (buff[buff_index - 1] > radix / 2)
266+
{
267+
buff[buff_index - 2]++;
268+
}
269+
270+
buff_index--;
271+
272+
/* Propagate carry. */
273+
for (int i = buff_index - 1; i > 0 && buff[i] >= radix; i--)
274+
{
275+
buff[i] = (lit_utf8_byte_t) (buff[i] - radix);
276+
buff[i - 1]++;
277+
}
278+
279+
/* Carry propagated over the whole number, need to add a leading digit. */
280+
if (buff[0] >= radix)
281+
{
282+
memmove (buff + 1, buff, (size_t) buff_index);
283+
buff_index++;
284+
buff[0] = 1;
285+
}
286+
}
287+
288+
/* Remove trailing zeros from fraction. */
289+
while (buff_index - 1 > point && buff[buff_index - 1] == 0)
290+
{
291+
buff_index--;
292+
}
293+
294+
/* Add leading zeros in case place of radix point is negative. */
295+
if (point <= 0)
296+
{
297+
memmove (buff - point + 1, buff, (size_t) buff_index);
298+
buff_index += -point + 1;
299+
300+
for (int i = 0; i < -point + 1; i++)
301+
{
302+
buff[i] = 0;
303+
}
304+
305+
point = 1;
306+
}
307+
308+
/* Convert digits to characters. */
309+
for (int i = 0; i < buff_index; i++)
310+
{
311+
buff[i] = digit_chars[buff[i]];
312+
}
313+
314+
/* Place radix point to the required position. */
315+
if (point < buff_index)
316+
{
317+
memmove (buff + point + 1, buff + point, (size_t) buff_index);
318+
buff[point] = '.';
319+
buff_index++;
320+
}
321+
322+
/* Add negative sign if necessary. */
323+
if (is_negative)
324+
{
325+
memmove (buff + 1, buff, (size_t) buff_index);
326+
buff_index++;
327+
buff[0] = '-';
328+
}
329+
330+
JERRY_ASSERT (buff_index <= buff_size);
331+
ecma_string_t* str_p = ecma_new_ecma_string_from_utf8 (buff, (lit_utf8_size_t) buff_index);
332+
ret_value = ecma_make_normal_completion_value (ecma_make_string_value (str_p));
333+
MEM_FINALIZE_LOCAL_ARRAY (buff);
334+
}
335+
ECMA_OP_TO_NUMBER_FINALIZE (arg_num);
336+
return ret_value;
129337
}
130338
} /* ecma_builtin_number_prototype_object_to_string */
131339

0 commit comments

Comments
 (0)