Skip to content

Commit 713b433

Browse files
committed
Implement Number.prototype.toPrecision()
JerryScript-DCO-1.0-Signed-off-by: Dániel Bátyai dbatyai.u-szeged@partner.samsung.com
1 parent 53cbb55 commit 713b433

File tree

2 files changed

+271
-1
lines changed

2 files changed

+271
-1
lines changed

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

Lines changed: 217 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -579,7 +579,223 @@ static ecma_completion_value_t
579579
ecma_builtin_number_prototype_object_to_precision (ecma_value_t this_arg, /**< this argument */
580580
ecma_value_t arg) /**< routine's argument */
581581
{
582-
ECMA_BUILTIN_CP_UNIMPLEMENTED (this_arg, arg);
582+
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
583+
584+
/* 1. */
585+
ECMA_OP_TO_NUMBER_TRY_CATCH (this_num, this_arg, ret_value);
586+
587+
/* 2. */
588+
if (ecma_is_value_undefined (arg))
589+
{
590+
ret_value = ecma_builtin_number_prototype_object_to_string (this_arg, NULL, 0);
591+
}
592+
else
593+
{
594+
/* 3. */
595+
ECMA_OP_TO_NUMBER_TRY_CATCH (arg_num, arg, ret_value);
596+
597+
/* 4. */
598+
if (ecma_number_is_nan (this_num))
599+
{
600+
ecma_string_t *nan_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_NAN);
601+
ret_value = ecma_make_normal_completion_value (ecma_make_string_value (nan_str_p));
602+
}
603+
else
604+
{
605+
bool is_negative = false;
606+
607+
/* 6. */
608+
if (ecma_number_is_negative (this_num) && !ecma_number_is_zero (this_num))
609+
{
610+
is_negative = true;
611+
this_num *= -1;
612+
}
613+
614+
/* 7. */
615+
if (ecma_number_is_infinity (this_num))
616+
{
617+
ecma_string_t *infinity_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_INFINITY_UL);
618+
619+
if (is_negative)
620+
{
621+
ecma_string_t *neg_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_MINUS_CHAR);
622+
ecma_string_t *neg_inf_str_p = ecma_concat_ecma_strings (neg_str_p, infinity_str_p);
623+
ecma_deref_ecma_string (infinity_str_p);
624+
ecma_deref_ecma_string (neg_str_p);
625+
ret_value = ecma_make_normal_completion_value (ecma_make_string_value (neg_inf_str_p));
626+
}
627+
else
628+
{
629+
ret_value = ecma_make_normal_completion_value (ecma_make_string_value (infinity_str_p));
630+
}
631+
}
632+
/* 8. */
633+
else if (arg_num < 1.0 || arg_num >= 22.0)
634+
{
635+
ret_value = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_RANGE));
636+
}
637+
else
638+
{
639+
uint64_t digits = 0;
640+
int32_t num_digits = 0;
641+
int32_t exponent = 1;
642+
643+
int32_t precision = ecma_number_to_int32 (arg_num);
644+
645+
/* Get the parameters of the number if non-zero. */
646+
if (!ecma_number_is_zero (this_num))
647+
{
648+
ecma_number_to_decimal (this_num, &digits, &num_digits, &exponent);
649+
}
650+
651+
digits = ecma_builtin_number_prototype_helper_round (digits, num_digits - precision);
652+
653+
int buffer_size;
654+
if (exponent < -5 || exponent > precision)
655+
{
656+
/* Exponential notation, precision + 1 digits for number, 5 for exponent, 1 for \0 */
657+
buffer_size = precision + 1 + 5 + 1;
658+
}
659+
else if (exponent <= 0)
660+
{
661+
/* Fixed notation, -exponent + 2 digits for leading zeros, precision digits, 1 for \0 */
662+
buffer_size = -exponent + 2 + precision + 1;
663+
}
664+
else
665+
{
666+
/* Fixed notation, precision + 1 digits for number, 1 for \0 */
667+
buffer_size = precision + 1 + 1;
668+
}
669+
670+
if (is_negative)
671+
{
672+
buffer_size++;
673+
}
674+
675+
MEM_DEFINE_LOCAL_ARRAY (buff, buffer_size, lit_utf8_byte_t);
676+
lit_utf8_byte_t *actual_char_p = buff;
677+
678+
uint64_t scale = 1;
679+
680+
/* Calculate the magnitude of the number. This is used to get the digits from left to right. */
681+
while (scale <= digits)
682+
{
683+
scale *= 10;
684+
}
685+
686+
if (is_negative)
687+
{
688+
*actual_char_p++ = '-';
689+
}
690+
691+
int digit = 0;
692+
693+
/* 10.c, Exponential notation.*/
694+
if (exponent < -5 || exponent > precision)
695+
{
696+
/* Add significant digits. */
697+
for (int i = 1; i <= precision; i++)
698+
{
699+
digit = 0;
700+
scale /= 10;
701+
while (digits >= scale && scale > 0)
702+
{
703+
digits -= scale;
704+
digit++;
705+
}
706+
707+
*actual_char_p++ = (lit_utf8_byte_t) (digit + '0');
708+
709+
if (i == 1 && i != precision)
710+
{
711+
*actual_char_p++ = '.';
712+
}
713+
}
714+
715+
*actual_char_p++ = 'e';
716+
717+
exponent--;
718+
if (exponent < 0)
719+
{
720+
exponent *= -1;
721+
*actual_char_p++ = '-';
722+
}
723+
else
724+
{
725+
*actual_char_p++ = '+';
726+
}
727+
728+
/* Get magnitude of exponent. */
729+
int32_t scale_expt = 1;
730+
while (scale_expt <= exponent)
731+
{
732+
scale_expt *= 10;
733+
}
734+
scale_expt /= 10;
735+
736+
/* Add exponent digits. */
737+
if (exponent == 0)
738+
{
739+
*actual_char_p++ = '0';
740+
}
741+
else
742+
{
743+
while (scale_expt > 0)
744+
{
745+
digit = exponent / scale_expt;
746+
exponent %= scale_expt;
747+
*actual_char_p++ = (lit_utf8_byte_t) (digit + '0');
748+
scale_expt /= 10;
749+
}
750+
}
751+
}
752+
/* Fixed notation. */
753+
else
754+
{
755+
/* Add leading zeros if neccessary. */
756+
if (exponent <= 0)
757+
{
758+
*actual_char_p++ = '0';
759+
*actual_char_p++ = '.';
760+
for (int i = exponent; i < 0; i++)
761+
{
762+
*actual_char_p++ = '0';
763+
}
764+
}
765+
766+
/* Add significant digits. */
767+
for (int i = 1; i <= precision; i++)
768+
{
769+
digit = 0;
770+
scale /= 10;
771+
while (digits >= scale && scale > 0)
772+
{
773+
digits -= scale;
774+
digit++;
775+
}
776+
777+
*actual_char_p++ = (lit_utf8_byte_t) (digit + '0');
778+
779+
if (i == exponent && i != precision)
780+
{
781+
*actual_char_p++ = '.';
782+
}
783+
}
784+
}
785+
786+
JERRY_ASSERT (actual_char_p - buff < buffer_size);
787+
*actual_char_p = '\0';
788+
ecma_string_t *str_p = ecma_new_ecma_string_from_utf8 (buff, (lit_utf8_size_t) (actual_char_p - buff));
789+
790+
ret_value = ecma_make_normal_completion_value (ecma_make_string_value (str_p));
791+
MEM_FINALIZE_LOCAL_ARRAY (buff);
792+
}
793+
}
794+
ECMA_OP_TO_NUMBER_FINALIZE (arg_num);
795+
}
796+
ECMA_OP_TO_NUMBER_FINALIZE (this_num);
797+
798+
return ret_value;
583799
} /* ecma_builtin_number_prototype_object_to_precision */
584800

585801
/**
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Copyright 2015 Samsung Electronics Co., Ltd.
2+
// Copyright 2015 University of Szeged.
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
16+
//This test will not pass on FLOAT32 due to precision issues
17+
18+
assert((123.56).toPrecision() === "123.56");
19+
assert((123.56).toPrecision(1) === "1e+2");
20+
assert((123.56).toPrecision(2) === "1.2e+2");
21+
assert((123.56).toPrecision(6) === "123.560");
22+
assert((-1.23).toPrecision(1) === "-1");
23+
assert((0.00023).toPrecision(1) === "0.0002");
24+
assert((0.356).toPrecision(2) === "0.36");
25+
assert((0.0000356).toPrecision(5) === "0.000035600");
26+
assert((0.000030056).toPrecision(4) === "0.00003006");
27+
assert(Infinity.toPrecision(1) === "Infinity");
28+
assert((-Infinity).toPrecision(1) === "-Infinity");
29+
assert(NaN.toPrecision(1) === "NaN");
30+
assert((0.0).toPrecision(1) === "0");
31+
assert((-0.0).toPrecision(1) === "0");
32+
assert((0.0).toPrecision(6) === "0.00000");
33+
assert((123456789012345678901.0).toPrecision(20) === "1.2345678901234568000e+20");
34+
assert((123456789012345678901.0).toPrecision(21) === "123456789012345680000");
35+
assert((123456789012345678901.0).toPrecision("6") === "1.23457e+20");
36+
37+
var obj = { toPrecision : Number.prototype.toPrecision };
38+
assert(obj.toPrecision(1) === "NaN");
39+
assert((123.56).toPrecision(1.3) === "1e+2");
40+
assert((123.56).toPrecision(21.9) === "123.560000000000000000");
41+
42+
try {
43+
(12).toPrecision(0);
44+
assert(false);
45+
} catch (e) {
46+
assert(e instanceof RangeError)
47+
}
48+
49+
try {
50+
(12).toPrecision(22);
51+
assert(false);
52+
} catch (e) {
53+
assert(e instanceof RangeError)
54+
}

0 commit comments

Comments
 (0)