details: https://hg.nginx.org/njs/rev/c9061ff75070 branches: changeset: 1174:c9061ff75070 user: Dmitry Volyntsev <xei...@nginx.com> date: Mon Oct 07 18:16:47 2019 +0300 description: Added Number.prototype.toExponential().
diffstat: src/njs_dtoa.c | 80 +++++++++++++++++++++++++++++++++++++---------- src/njs_dtoa.h | 2 + src/njs_number.c | 55 +++++++++++++++++++++++++++++++++ src/test/njs_unit_test.c | 48 ++++++++++++++++++++++++++++ 4 files changed, 168 insertions(+), 17 deletions(-) diffs (242 lines): diff -r d6ba4bffddef -r c9061ff75070 src/njs_dtoa.c --- a/src/njs_dtoa.c Mon Oct 07 18:11:19 2019 +0300 +++ b/src/njs_dtoa.c Mon Oct 07 18:16:47 2019 +0300 @@ -472,30 +472,36 @@ njs_dtoa_format(char *start, size_t len, njs_inline size_t +njs_dtoa_exp_format(char *start, int exponent, size_t prec, size_t len) +{ + char *p; + + p = &start[len]; + if (prec != 1) { + memmove(&start[2], &start[1], len - 1); + start[1] = '.'; + p++; + } + + njs_memset(p, '0', prec - len); + p += prec - len; + + *p++ = 'e'; + + return prec + 1 + (prec != 1) + njs_write_exponent(exponent, p); +} + + +njs_inline size_t njs_dtoa_prec_format(char *start, size_t prec, size_t len, int point) { int exponent; - char *p; - size_t m, rest, size; + size_t m, rest; exponent = point - 1; if (exponent < -6 || exponent >= (int) prec) { - p = &start[len]; - if (prec != 1) { - memmove(&start[2], &start[1], len - 1); - start[1] = '.'; - p++; - } - - njs_memset(p, '0', prec - len); - p += prec - len; - - *p++ = 'e'; - - size = njs_write_exponent(exponent, p); - - return prec + 1 + (prec != 1) + size; + return njs_dtoa_exp_format(start, exponent, prec, len); } /* Fixed notation. */ @@ -609,3 +615,43 @@ njs_dtoa_precision(double value, char *s return njs_dtoa_prec_format(p, prec, length, point) + minus; } + + +size_t +njs_dtoa_exponential(double value, char *start, njs_int_t frac) +{ + int point, minus; + char *p; + size_t length; + + /* Not handling NaN and inf. */ + + p = start; + minus = 0; + + if (value != 0) { + if (value < 0) { + *p++ = '-'; + value = -value; + minus = 1; + } + + if (frac == -1) { + length = njs_grisu2(value, p, &point); + + } else { + length = njs_grisu2_prec(value, p, frac + 1, &point); + } + + } else { + start[0] = '0'; + length = 1; + point = 1; + } + + if (frac == -1) { + frac = length - 1; + } + + return njs_dtoa_exp_format(p, point - 1, frac + 1, length) + minus; +} diff -r d6ba4bffddef -r c9061ff75070 src/njs_dtoa.h --- a/src/njs_dtoa.h Mon Oct 07 18:11:19 2019 +0300 +++ b/src/njs_dtoa.h Mon Oct 07 18:16:47 2019 +0300 @@ -9,5 +9,7 @@ NJS_EXPORT size_t njs_dtoa(double value, char *start); NJS_EXPORT size_t njs_dtoa_precision(double value, char *start, size_t prec); +NJS_EXPORT size_t njs_dtoa_exponential(double value, char *start, + njs_int_t frac); #endif /* _NJS_DTOA_H_INCLUDED_ */ diff -r d6ba4bffddef -r c9061ff75070 src/njs_number.c --- a/src/njs_number.c Mon Oct 07 18:11:19 2019 +0300 +++ b/src/njs_number.c Mon Oct 07 18:16:47 2019 +0300 @@ -684,6 +684,52 @@ njs_number_prototype_to_precision(njs_vm } +static njs_int_t +njs_number_prototype_to_exponential(njs_vm_t *vm, njs_value_t *args, + njs_uint_t nargs, njs_index_t unused) +{ + double number; + size_t size; + int32_t frac; + njs_value_t *value; + u_char buf[128]; + + value = &args[0]; + + if (value->type != NJS_NUMBER) { + if (value->type == NJS_OBJECT_NUMBER) { + value = njs_object_value(value); + + } else { + njs_type_error(vm, "unexpected value type:%s", + njs_type_string(value->type)); + return NJS_ERROR; + } + } + + number = njs_number(value); + + if (njs_slow_path(isnan(number) || isinf(number))) { + return njs_number_to_string(vm, &vm->retval, value); + } + + if (njs_is_defined(njs_arg(args, nargs, 1))) { + frac = njs_primitive_value_to_integer(njs_argument(args, 1)); + if (njs_slow_path(frac < 0 || frac > 100)) { + njs_range_error(vm, "digits argument must be between 0 and 100"); + return NJS_ERROR; + } + + } else { + frac = -1; + } + + size = njs_dtoa_exponential(number, (char *) buf, frac); + + return njs_string_new(vm, &vm->retval, buf, size, size); +} + + /* * The radix equal to 2 produces the longest value for a number. */ @@ -858,6 +904,15 @@ static const njs_object_prop_t njs_numb .writable = 1, .configurable = 1, }, + + { + .type = NJS_PROPERTY, + .name = njs_string("toExponential"), + .value = njs_native_function(njs_number_prototype_to_exponential, + NJS_SKIP_ARG, NJS_INTEGER_ARG), + .writable = 1, + .configurable = 1, + }, }; diff -r d6ba4bffddef -r c9061ff75070 src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Mon Oct 07 18:11:19 2019 +0300 +++ b/src/test/njs_unit_test.c Mon Oct 07 18:16:47 2019 +0300 @@ -628,6 +628,54 @@ static njs_unit_test_t njs_test[] = { njs_str("(0).toFixed(101)"), njs_str("RangeError: digits argument must be between 0 and 100") }, + /* Number.prototype.toExponential(frac) method. */ + + { njs_str("Array(3).fill().map((n, i) => i + 1).map((v)=>(0).toExponential(v))"), + njs_str("0.0e+0,0.00e+0,0.000e+0") }, + + { njs_str("Array(6).fill().map((n, i) => i + 1).map((v)=>((Math.pow(-1,v))*(2*v)/3).toExponential(5))"), + njs_str("-6.66667e-1,1.33333e+0,-2.00000e+0,2.66667e+0,-3.33333e+0,4.00000e+0") }, + + { njs_str("Array(5).fill().map((n, i) => i + 1).map((v)=>((Math.pow(-1,v))*(2*v)/3).toExponential())"), + njs_str("-6.666666666666666e-1,1.3333333333333333e+0,-2e+0,2.6666666666666667e+0,-3.3333333333333337e+0") }, + +#ifndef NJS_SUNC + { njs_str("4.94065645841246544176568792868e-324.toExponential()"), + njs_str("5e-324") }, + + { njs_str("4.94065645841246544176568792868e-324.toExponential(10)"), + njs_str("4.9406564584e-324") }, +#endif + + { njs_str("1.7976931348623157e+308.toExponential()"), + njs_str("1.7976931348623157e+308") }, + +#if 0 /* FIXME: bignum support is requred to support prec >= 20 */ + { njs_str("(1/7).toExponential(100)"), + njs_str("1.4285714285714284921269268124888185411691665649414062500000000000000000000000000000000000000000000000e-1") }, +#endif + + { njs_str("var v = 1.7976931348623157e+308; Number(v.toExponential()) == v"), + njs_str("true") }, + + { njs_str("(123).toExponential(-1)"), + njs_str("RangeError: digits argument must be between 0 and 100") }, + + { njs_str("(123).toExponential(2.4)"), + njs_str("1.23e+2") }, + + { njs_str("(123).toExponential(101)"), + njs_str("RangeError: digits argument must be between 0 and 100") }, + + { njs_str("[2**10000,-(2**10000),NaN].map((v)=>v.toExponential())"), + njs_str("Infinity,-Infinity,NaN") }, + + { njs_str("[2**10000,-(2**10000),NaN].map((v)=>v.toExponential(1000))"), + njs_str("Infinity,-Infinity,NaN") }, + + { njs_str("Number.prototype.toExponential.call('12')"), + njs_str("TypeError: unexpected value type:string") }, + /* An object "valueOf/toString" methods. */ { njs_str("var a = { valueOf: function() { return 1 } }; +a"), _______________________________________________ nginx-devel mailing list nginx-devel@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx-devel