details: http://hg.nginx.org/njs/rev/0f9c060a0198 branches: changeset: 561:0f9c060a0198 user: Dmitry Volyntsev <xei...@nginx.com> date: Thu Jul 19 18:11:52 2018 +0300 description: Fixed Number.toString().
Adding correct dtoa() and strtod() realization. This fixes #28 and #30 issues on GitHub. diffstat: Makefile | 6 + njs/njs_core.h | 2 + njs/njs_json.c | 2 +- njs/njs_number.c | 116 +------------- njs/njs_number.h | 1 - njs/test/njs_unit_test.c | 74 ++++++- nxt/Makefile | 36 ++++ nxt/auto/clang | 26 +++ nxt/nxt_clang.h | 32 +++ nxt/nxt_diyfp.c | 150 +++++++++++++++++ nxt/nxt_diyfp.h | 212 ++++++++++++++++++++++++ nxt/nxt_dtoa.c | 363 ++++++++++++++++++++++++++++++++++++++++++ nxt/nxt_dtoa.h | 12 + nxt/nxt_strtod.c | 403 +++++++++++++++++++++++++++++++++++++++++++++++ nxt/nxt_strtod.h | 12 + nxt/nxt_types.h | 5 + 16 files changed, 1322 insertions(+), 130 deletions(-) diffs (truncated from 1692 to 1000 lines): diff -r 9322e8eab0b6 -r 0f9c060a0198 Makefile --- a/Makefile Wed Jul 18 15:41:55 2018 +0300 +++ b/Makefile Thu Jul 19 18:11:52 2018 +0300 @@ -34,6 +34,9 @@ NXT_BUILDDIR = build $(NXT_BUILDDIR)/njs_parser_expression.o \ $(NXT_BUILDDIR)/njs_generator.o \ $(NXT_BUILDDIR)/njs_disassembler.o \ + $(NXT_BUILDDIR)/nxt_diyfp.o \ + $(NXT_BUILDDIR)/nxt_dtoa.o \ + $(NXT_BUILDDIR)/nxt_strtod.o \ $(NXT_BUILDDIR)/nxt_djb_hash.o \ $(NXT_BUILDDIR)/nxt_utf8.o \ $(NXT_BUILDDIR)/nxt_array.o \ @@ -76,6 +79,9 @@ NXT_BUILDDIR = build $(NXT_BUILDDIR)/njs_parser_expression.o \ $(NXT_BUILDDIR)/njs_generator.o \ $(NXT_BUILDDIR)/njs_disassembler.o \ + $(NXT_BUILDDIR)/nxt_diyfp.o \ + $(NXT_BUILDDIR)/nxt_dtoa.o \ + $(NXT_BUILDDIR)/nxt_strtod.o \ $(NXT_BUILDDIR)/nxt_djb_hash.o \ $(NXT_BUILDDIR)/nxt_utf8.o \ $(NXT_BUILDDIR)/nxt_array.o \ diff -r 9322e8eab0b6 -r 0f9c060a0198 njs/njs_core.h --- a/njs/njs_core.h Wed Jul 18 15:41:55 2018 +0300 +++ b/njs/njs_core.h Thu Jul 19 18:11:52 2018 +0300 @@ -15,6 +15,8 @@ #include <nxt_string.h> #include <nxt_stub.h> #include <nxt_utf8.h> +#include <nxt_dtoa.h> +#include <nxt_strtod.h> #include <nxt_djb_hash.h> #include <nxt_trace.h> #include <nxt_array.h> diff -r 9322e8eab0b6 -r 0f9c060a0198 njs/njs_json.c --- a/njs/njs_json.c Wed Jul 18 15:41:55 2018 +0300 +++ b/njs/njs_json.c Thu Jul 19 18:11:52 2018 +0300 @@ -1844,7 +1844,7 @@ njs_json_append_number(njs_json_stringif return NXT_ERROR; } - size = njs_num_to_buf(num, p, 64); + size = nxt_dtoa(num, (char *) p); njs_json_buf_written(stringify, size); } diff -r 9322e8eab0b6 -r 0f9c060a0198 njs/njs_number.c --- a/njs/njs_number.c Wed Jul 18 15:41:55 2018 +0300 +++ b/njs/njs_number.c Thu Jul 19 18:11:52 2018 +0300 @@ -66,91 +66,7 @@ njs_value_to_index(const njs_value_t *va double njs_number_dec_parse(const u_char **start, const u_char *end) { - u_char c; - double num, frac, scale, exponent; - nxt_bool_t minus; - const u_char *e, *p; - - p = *start; - - num = 0; - - while (p < end) { - /* Values less than '0' become >= 208. */ - c = *p - '0'; - - if (nxt_slow_path(c > 9)) { - break; - } - - num = num * 10 + c; - p++; - } - - if (p < end && *p == '.') { - - frac = 0; - scale = 1; - - for (p++; p < end; p++) { - /* Values less than '0' become >= 208. */ - c = *p - '0'; - - if (nxt_slow_path(c > 9)) { - break; - } - - frac = frac * 10 + c; - scale *= 10; - } - - num += frac / scale; - } - - e = p + 1; - - if (e < end && (*p == 'e' || *p == 'E')) { - minus = 0; - - if (e + 1 < end) { - if (*e == '-') { - e++; - minus = 1; - - } else if (*e == '+') { - e++; - } - } - - /* Values less than '0' become >= 208. */ - c = *e - '0'; - - if (nxt_fast_path(c <= 9)) { - exponent = c; - p = e + 1; - - while (p < end) { - /* Values less than '0' become >= 208. */ - c = *p - '0'; - - if (nxt_slow_path(c > 9)) { - break; - } - - exponent = exponent * 10 + c; - p++; - } - - if (num != 0) { - exponent = minus ? -exponent : exponent; - num = num * pow(10.0, exponent); - } - } - } - - *start = p; - - return num; + return nxt_strtod(start, end); } @@ -312,7 +228,7 @@ njs_number_to_string(njs_vm_t *vm, njs_v } } else { - size = njs_num_to_buf(num, buf, sizeof(buf)); + size = nxt_dtoa(num, (char *) buf); return njs_string_new(vm, string, buf, size, size); } @@ -323,34 +239,6 @@ njs_number_to_string(njs_vm_t *vm, njs_v } -size_t -njs_num_to_buf(double num, u_char *buf, size_t size) -{ - double n; - const char *fmt; - - n = fabs(num); - - if (n == 0) { - fmt = "%g"; - - } else if (n < 1) { - fmt = "%f"; - - } else if (n < 1000000) { - fmt = "%g"; - - } else if (n < 1e20) { - fmt = "%1.f"; - - } else { - fmt = "%1.e"; - } - - return snprintf((char *) buf, size, fmt, num); -} - - njs_ret_t njs_number_constructor(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) diff -r 9322e8eab0b6 -r 0f9c060a0198 njs/njs_number.h --- a/njs/njs_number.h Wed Jul 18 15:41:55 2018 +0300 +++ b/njs/njs_number.h Thu Jul 19 18:11:52 2018 +0300 @@ -20,7 +20,6 @@ int64_t njs_number_radix_parse(const u_c uint8_t radix); njs_ret_t njs_number_to_string(njs_vm_t *vm, njs_value_t *string, const njs_value_t *number); -size_t njs_num_to_buf(double num, u_char *buf, size_t size); njs_ret_t njs_number_constructor(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); njs_ret_t njs_number_global_is_nan(njs_vm_t *vm, njs_value_t *args, diff -r 9322e8eab0b6 -r 0f9c060a0198 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Wed Jul 18 15:41:55 2018 +0300 +++ b/njs/test/njs_unit_test.c Thu Jul 19 18:11:52 2018 +0300 @@ -93,19 +93,44 @@ static njs_unit_test_t njs_test[] = /* Numbers. */ + { nxt_string("0"), + nxt_string("0") }, + + { nxt_string("-0"), + nxt_string("-0") }, + + { nxt_string("0.1"), + nxt_string("0.1") }, + + { nxt_string("0.000001"), + nxt_string("0.000001") }, + + { nxt_string("0.00000123456"), + nxt_string("0.00000123456") }, + + { nxt_string("0.0000001"), + nxt_string("1e-7") }, + + { nxt_string("1.1000000"), + nxt_string("1.1") }, + + { nxt_string("99999999999999999999"), + nxt_string("100000000000000000000") }, + + { nxt_string("99999999999999999999.111"), + nxt_string("100000000000000000000") }, + { nxt_string("999999999999999999999"), nxt_string("1e+21") }, -#if 0 { nxt_string("9223372036854775808"), - nxt_string("9223372036854775808") }, + nxt_string("9223372036854776000") }, { nxt_string("18446744073709551616"), nxt_string("18446744073709552000") }, { nxt_string("1.7976931348623157E+308"), nxt_string("1.7976931348623157e+308") }, -#endif { nxt_string("+1"), nxt_string("1") }, @@ -223,16 +248,16 @@ static njs_unit_test_t njs_test[] = nxt_string("57") }, { nxt_string("5.7e-1"), - nxt_string("0.570000") }, + nxt_string("0.57") }, { nxt_string("-5.7e-1"), - nxt_string("-0.570000") }, + nxt_string("-0.57") }, { nxt_string("1.1e-01"), - nxt_string("0.110000") }, + nxt_string("0.11") }, { nxt_string("5.7e-2"), - nxt_string("0.057000") }, + nxt_string("0.057") }, { nxt_string("1.1e+01"), nxt_string("11") }, @@ -629,7 +654,7 @@ static njs_unit_test_t njs_test[] = nxt_string("NaN") }, { nxt_string("var a = 0.1; a **= -2"), - nxt_string("100") }, + nxt_string("99.99999999999999") }, { nxt_string("var a = 1; a **= NaN"), nxt_string("NaN") }, @@ -6210,6 +6235,24 @@ static njs_unit_test_t njs_test[] = { nxt_string("Number('123')"), nxt_string("123") }, + { nxt_string("Number('0.'+'1'.repeat(128))"), + nxt_string("0.1111111111111111") }, + + { nxt_string("Number('1'.repeat(128))"), + nxt_string("1.1111111111111113e+127") }, + + { nxt_string("Number('1'.repeat(129))"), + nxt_string("1.1111111111111112e+128") }, + + { nxt_string("Number('1'.repeat(129))"), + nxt_string("1.1111111111111112e+128") }, + + { nxt_string("Number('1'.repeat(129)+'e-100')"), + nxt_string("1.1111111111111112e+28") }, + + { nxt_string("Number('1'.repeat(310))"), + nxt_string("Infinity") }, + { nxt_string("var o = { valueOf: function() { return 123 } };" "Number(o)"), nxt_string("123") }, @@ -7530,7 +7573,7 @@ static njs_unit_test_t njs_test[] = /* Math. */ { nxt_string("Math.PI"), - nxt_string("3.14159") }, + nxt_string("3.141592653589793") }, { nxt_string("Math.abs()"), nxt_string("NaN") }, @@ -7788,8 +7831,8 @@ static njs_unit_test_t njs_test[] = { nxt_string("Math.cbrt(-Infinity)"), nxt_string("-Infinity") }, - { nxt_string("Math.cbrt('27')"), - nxt_string("3") }, + { nxt_string("(Math.cbrt('27') - 3) < 1e-15"), + nxt_string("true") }, { nxt_string("Math.cbrt(-1)"), nxt_string("-1") }, @@ -8570,10 +8613,10 @@ static njs_unit_test_t njs_test[] = nxt_string("57") }, { nxt_string("parseFloat('-5.7e-1')"), - nxt_string("-0.570000") }, + nxt_string("-0.57") }, { nxt_string("parseFloat('-5.e-1')"), - nxt_string("-0.500000") }, + nxt_string("-0.5") }, { nxt_string("parseFloat('5.7e+01')"), nxt_string("57") }, @@ -8582,7 +8625,7 @@ static njs_unit_test_t njs_test[] = nxt_string("57") }, { nxt_string("parseFloat('-5.7e-1abc')"), - nxt_string("-0.570000") }, + nxt_string("-0.57") }, { nxt_string("parseFloat('-5.7e')"), nxt_string("-5.7") }, @@ -8914,6 +8957,9 @@ static njs_unit_test_t njs_test[] = { nxt_string("JSON.stringify(123)"), nxt_string("123") }, + { nxt_string("JSON.stringify(0.00000123)"), + nxt_string("0.00000123") }, + { nxt_string("JSON.stringify(new Number(123))"), nxt_string("123") }, diff -r 9322e8eab0b6 -r 0f9c060a0198 nxt/Makefile --- a/nxt/Makefile Wed Jul 18 15:41:55 2018 +0300 +++ b/nxt/Makefile Thu Jul 19 18:11:52 2018 +0300 @@ -4,6 +4,9 @@ NXT_LIB = nxt $(NXT_BUILDDIR)/libnxt.a: \ $(NXT_LIB)/nxt_auto_config.h \ + $(NXT_BUILDDIR)/nxt_diyfp.o \ + $(NXT_BUILDDIR)/nxt_dtoa.o \ + $(NXT_BUILDDIR)/nxt_strtod.o \ $(NXT_BUILDDIR)/nxt_djb_hash.o \ $(NXT_BUILDDIR)/nxt_utf8.o \ $(NXT_BUILDDIR)/nxt_array.o \ @@ -20,6 +23,9 @@ NXT_LIB = nxt $(NXT_BUILDDIR)/nxt_mem_cache_pool.o \ ar -r -c $(NXT_BUILDDIR)/libnxt.a \ + $(NXT_BUILDDIR)/nxt_diyfp.o \ + $(NXT_BUILDDIR)/nxt_dtoa.o \ + $(NXT_BUILDDIR)/nxt_strtod.o \ $(NXT_BUILDDIR)/nxt_djb_hash.o \ $(NXT_BUILDDIR)/nxt_utf8.o \ $(NXT_BUILDDIR)/nxt_array.o \ @@ -34,6 +40,36 @@ NXT_LIB = nxt $(NXT_BUILDDIR)/nxt_trace.o \ $(NXT_BUILDDIR)/nxt_mem_cache_pool.o \ +$(NXT_BUILDDIR)/nxt_diyfp.o: \ + $(NXT_LIB)/nxt_types.h \ + $(NXT_LIB)/nxt_clang.h \ + $(NXT_LIB)/nxt_diyfp.h \ + $(NXT_LIB)/nxt_diyfp.c \ + + $(NXT_CC) -c -o $(NXT_BUILDDIR)/nxt_diyfp.o $(NXT_CFLAGS) \ + -I$(NXT_LIB) \ + $(NXT_LIB)/nxt_diyfp.c + +$(NXT_BUILDDIR)/nxt_dtoa.o: \ + $(NXT_LIB)/nxt_types.h \ + $(NXT_LIB)/nxt_clang.h \ + $(NXT_LIB)/nxt_dtoa.h \ + $(NXT_LIB)/nxt_dtoa.c \ + + $(NXT_CC) -c -o $(NXT_BUILDDIR)/nxt_dtoa.o $(NXT_CFLAGS) \ + -I$(NXT_LIB) \ + $(NXT_LIB)/nxt_dtoa.c + +$(NXT_BUILDDIR)/nxt_strtod.o: \ + $(NXT_LIB)/nxt_types.h \ + $(NXT_LIB)/nxt_clang.h \ + $(NXT_LIB)/nxt_strtod.h \ + $(NXT_LIB)/nxt_strtod.c \ + + $(NXT_CC) -c -o $(NXT_BUILDDIR)/nxt_strtod.o $(NXT_CFLAGS) \ + -I$(NXT_LIB) \ + $(NXT_LIB)/nxt_strtod.c + $(NXT_BUILDDIR)/nxt_murmur_hash.o: \ $(NXT_LIB)/nxt_types.h \ $(NXT_LIB)/nxt_clang.h \ diff -r 9322e8eab0b6 -r 0f9c060a0198 nxt/auto/clang --- a/nxt/auto/clang Wed Jul 18 15:41:55 2018 +0300 +++ b/nxt/auto/clang Thu Jul 19 18:11:52 2018 +0300 @@ -166,6 +166,18 @@ END # C language features. +nxt_feature="GCC unsigned __int128" +nxt_feature_name=NXT_HAVE_UNSIGNED_INT128 +nxt_feature_run=no +nxt_feature_incs= +nxt_feature_libs= +nxt_feature_test="int main(void) { + unsigned __int128 p = 0; + return (int) p; + }" +. ${NXT_AUTO}feature + + nxt_feature="GCC __builtin_expect()" nxt_feature_name=NXT_HAVE_BUILTIN_EXPECT nxt_feature_run=no @@ -217,6 +229,20 @@ nxt_feature_test="int main(void) { . ${NXT_AUTO}feature +nxt_feature="GCC __builtin_clzll()" +nxt_feature_name=NXT_HAVE_BUILTIN_CLZLL +nxt_feature_run=no +nxt_feature_incs= +nxt_feature_libs= +nxt_feature_test="int main(void) { + if (__builtin_clzll(1ULL) != 63) { + return 1; + } + return 0; + }" +. ${NXT_AUTO}feature + + nxt_feature="GCC __attribute__ visibility" nxt_feature_name=NXT_HAVE_GCC_ATTRIBUTE_VISIBILITY nxt_feature_run=no diff -r 9322e8eab0b6 -r 0f9c060a0198 nxt/nxt_clang.h --- a/nxt/nxt_clang.h Wed Jul 18 15:41:55 2018 +0300 +++ b/nxt/nxt_clang.h Thu Jul 19 18:11:52 2018 +0300 @@ -86,6 +86,38 @@ nxt_leading_zeros(uint32_t x) #endif +#if (NXT_HAVE_BUILTIN_CLZLL) +#define nxt_leading_zeros64(x) (((x) == 0) ? 64 : __builtin_clzll(x)) + +#else + +nxt_inline uint64_t +nxt_leading_zeros64(uint64_t x) +{ + uint64_t n; + + /* + * There is no sense to optimize this function, since almost + * all platforms nowadays support the built-in instruction. + */ + + if (x == 0) { + return 64; + } + + n = 0; + + while ((x & 0x8000000000000000) == 0) { + n++; + x <<= 1; + } + + return n; +} + +#endif + + #if (NXT_HAVE_GCC_ATTRIBUTE_VISIBILITY) #define NXT_EXPORT __attribute__((visibility("default"))) diff -r 9322e8eab0b6 -r 0f9c060a0198 nxt/nxt_diyfp.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nxt/nxt_diyfp.c Thu Jul 19 18:11:52 2018 +0300 @@ -0,0 +1,150 @@ + +/* + * Copyright (C) Dmitry Volyntsev + * Copyright (C) NGINX, Inc. + * + * An internal diy_fp implementation. + * For details, see Loitsch, Florian. "Printing floating-point numbers quickly + * and accurately with integers." ACM Sigplan Notices 45.6 (2010): 233-243. + */ + +#include <nxt_auto_config.h> +#include <nxt_types.h> +#include <nxt_clang.h> +#include <nxt_diyfp.h> + + +typedef struct nxt_cpe_s { + uint64_t significand; + int16_t bin_exp; + int16_t dec_exp; +} nxt_cpe_t; + + +static const nxt_cpe_t nxt_cached_powers[] = { + { nxt_uint64(0xfa8fd5a0, 0x081c0288), -1220, -348 }, + { nxt_uint64(0xbaaee17f, 0xa23ebf76), -1193, -340 }, + { nxt_uint64(0x8b16fb20, 0x3055ac76), -1166, -332 }, + { nxt_uint64(0xcf42894a, 0x5dce35ea), -1140, -324 }, + { nxt_uint64(0x9a6bb0aa, 0x55653b2d), -1113, -316 }, + { nxt_uint64(0xe61acf03, 0x3d1a45df), -1087, -308 }, + { nxt_uint64(0xab70fe17, 0xc79ac6ca), -1060, -300 }, + { nxt_uint64(0xff77b1fc, 0xbebcdc4f), -1034, -292 }, + { nxt_uint64(0xbe5691ef, 0x416bd60c), -1007, -284 }, + { nxt_uint64(0x8dd01fad, 0x907ffc3c), -980, -276 }, + { nxt_uint64(0xd3515c28, 0x31559a83), -954, -268 }, + { nxt_uint64(0x9d71ac8f, 0xada6c9b5), -927, -260 }, + { nxt_uint64(0xea9c2277, 0x23ee8bcb), -901, -252 }, + { nxt_uint64(0xaecc4991, 0x4078536d), -874, -244 }, + { nxt_uint64(0x823c1279, 0x5db6ce57), -847, -236 }, + { nxt_uint64(0xc2109436, 0x4dfb5637), -821, -228 }, + { nxt_uint64(0x9096ea6f, 0x3848984f), -794, -220 }, + { nxt_uint64(0xd77485cb, 0x25823ac7), -768, -212 }, + { nxt_uint64(0xa086cfcd, 0x97bf97f4), -741, -204 }, + { nxt_uint64(0xef340a98, 0x172aace5), -715, -196 }, + { nxt_uint64(0xb23867fb, 0x2a35b28e), -688, -188 }, + { nxt_uint64(0x84c8d4df, 0xd2c63f3b), -661, -180 }, + { nxt_uint64(0xc5dd4427, 0x1ad3cdba), -635, -172 }, + { nxt_uint64(0x936b9fce, 0xbb25c996), -608, -164 }, + { nxt_uint64(0xdbac6c24, 0x7d62a584), -582, -156 }, + { nxt_uint64(0xa3ab6658, 0x0d5fdaf6), -555, -148 }, + { nxt_uint64(0xf3e2f893, 0xdec3f126), -529, -140 }, + { nxt_uint64(0xb5b5ada8, 0xaaff80b8), -502, -132 }, + { nxt_uint64(0x87625f05, 0x6c7c4a8b), -475, -124 }, + { nxt_uint64(0xc9bcff60, 0x34c13053), -449, -116 }, + { nxt_uint64(0x964e858c, 0x91ba2655), -422, -108 }, + { nxt_uint64(0xdff97724, 0x70297ebd), -396, -100 }, + { nxt_uint64(0xa6dfbd9f, 0xb8e5b88f), -369, -92 }, + { nxt_uint64(0xf8a95fcf, 0x88747d94), -343, -84 }, + { nxt_uint64(0xb9447093, 0x8fa89bcf), -316, -76 }, + { nxt_uint64(0x8a08f0f8, 0xbf0f156b), -289, -68 }, + { nxt_uint64(0xcdb02555, 0x653131b6), -263, -60 }, + { nxt_uint64(0x993fe2c6, 0xd07b7fac), -236, -52 }, + { nxt_uint64(0xe45c10c4, 0x2a2b3b06), -210, -44 }, + { nxt_uint64(0xaa242499, 0x697392d3), -183, -36 }, + { nxt_uint64(0xfd87b5f2, 0x8300ca0e), -157, -28 }, + { nxt_uint64(0xbce50864, 0x92111aeb), -130, -20 }, + { nxt_uint64(0x8cbccc09, 0x6f5088cc), -103, -12 }, + { nxt_uint64(0xd1b71758, 0xe219652c), -77, -4 }, + { nxt_uint64(0x9c400000, 0x00000000), -50, 4 }, + { nxt_uint64(0xe8d4a510, 0x00000000), -24, 12 }, + { nxt_uint64(0xad78ebc5, 0xac620000), 3, 20 }, + { nxt_uint64(0x813f3978, 0xf8940984), 30, 28 }, + { nxt_uint64(0xc097ce7b, 0xc90715b3), 56, 36 }, + { nxt_uint64(0x8f7e32ce, 0x7bea5c70), 83, 44 }, + { nxt_uint64(0xd5d238a4, 0xabe98068), 109, 52 }, + { nxt_uint64(0x9f4f2726, 0x179a2245), 136, 60 }, + { nxt_uint64(0xed63a231, 0xd4c4fb27), 162, 68 }, + { nxt_uint64(0xb0de6538, 0x8cc8ada8), 189, 76 }, + { nxt_uint64(0x83c7088e, 0x1aab65db), 216, 84 }, + { nxt_uint64(0xc45d1df9, 0x42711d9a), 242, 92 }, + { nxt_uint64(0x924d692c, 0xa61be758), 269, 100 }, + { nxt_uint64(0xda01ee64, 0x1a708dea), 295, 108 }, + { nxt_uint64(0xa26da399, 0x9aef774a), 322, 116 }, + { nxt_uint64(0xf209787b, 0xb47d6b85), 348, 124 }, + { nxt_uint64(0xb454e4a1, 0x79dd1877), 375, 132 }, + { nxt_uint64(0x865b8692, 0x5b9bc5c2), 402, 140 }, + { nxt_uint64(0xc83553c5, 0xc8965d3d), 428, 148 }, + { nxt_uint64(0x952ab45c, 0xfa97a0b3), 455, 156 }, + { nxt_uint64(0xde469fbd, 0x99a05fe3), 481, 164 }, + { nxt_uint64(0xa59bc234, 0xdb398c25), 508, 172 }, + { nxt_uint64(0xf6c69a72, 0xa3989f5c), 534, 180 }, + { nxt_uint64(0xb7dcbf53, 0x54e9bece), 561, 188 }, + { nxt_uint64(0x88fcf317, 0xf22241e2), 588, 196 }, + { nxt_uint64(0xcc20ce9b, 0xd35c78a5), 614, 204 }, + { nxt_uint64(0x98165af3, 0x7b2153df), 641, 212 }, + { nxt_uint64(0xe2a0b5dc, 0x971f303a), 667, 220 }, + { nxt_uint64(0xa8d9d153, 0x5ce3b396), 694, 228 }, + { nxt_uint64(0xfb9b7cd9, 0xa4a7443c), 720, 236 }, + { nxt_uint64(0xbb764c4c, 0xa7a44410), 747, 244 }, + { nxt_uint64(0x8bab8eef, 0xb6409c1a), 774, 252 }, + { nxt_uint64(0xd01fef10, 0xa657842c), 800, 260 }, + { nxt_uint64(0x9b10a4e5, 0xe9913129), 827, 268 }, + { nxt_uint64(0xe7109bfb, 0xa19c0c9d), 853, 276 }, + { nxt_uint64(0xac2820d9, 0x623bf429), 880, 284 }, + { nxt_uint64(0x80444b5e, 0x7aa7cf85), 907, 292 }, + { nxt_uint64(0xbf21e440, 0x03acdd2d), 933, 300 }, + { nxt_uint64(0x8e679c2f, 0x5e44ff8f), 960, 308 }, + { nxt_uint64(0xd433179d, 0x9c8cb841), 986, 316 }, + { nxt_uint64(0x9e19db92, 0xb4e31ba9), 1013, 324 }, + { nxt_uint64(0xeb96bf6e, 0xbadf77d9), 1039, 332 }, + { nxt_uint64(0xaf87023b, 0x9bf0ee6b), 1066, 340 }, +}; + + +#define NXT_D_1_LOG2_10 0.30102999566398114 /* 1 / log2(10). */ + + +nxt_diyfp_t +nxt_cached_power_dec(int exp, int *dec_exp) +{ + u_int index; + const nxt_cpe_t *cp; + + index = (exp + NXT_DECIMAL_EXPONENT_OFF) / NXT_DECIMAL_EXPONENT_DIST; + cp = &nxt_cached_powers[index]; + + *dec_exp = cp->dec_exp; + + return nxt_diyfp(cp->significand, cp->bin_exp); +} + + +nxt_diyfp_t +nxt_cached_power_bin(int exp, int *dec_exp) +{ + int k; + u_int index; + const nxt_cpe_t *cp; + + k = (int) ceil((-61 - exp) * NXT_D_1_LOG2_10) + + NXT_DECIMAL_EXPONENT_OFF - 1; + + index = (unsigned) (k >> 3) + 1; + + cp = &nxt_cached_powers[index]; + + *dec_exp = -(NXT_DECIMAL_EXPONENT_MIN + (int) (index << 3)); + + return nxt_diyfp(cp->significand, cp->bin_exp); +} diff -r 9322e8eab0b6 -r 0f9c060a0198 nxt/nxt_diyfp.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nxt/nxt_diyfp.h Thu Jul 19 18:11:52 2018 +0300 @@ -0,0 +1,212 @@ + +/* + * Copyright (C) Dmitry Volyntsev + * Copyright (C) NGINX, Inc. + * + * An internal diy_fp implementation. + * For details, see Loitsch, Florian. "Printing floating-point numbers quickly + * and accurately with integers." ACM Sigplan Notices 45.6 (2010): 233-243. + */ + +#ifndef _NXT_DIYFP_H_INCLUDED_ +#define _NXT_DIYFP_H_INCLUDED_ + +#include <nxt_types.h> +#include <math.h> + + +typedef struct { + uint64_t significand; + int exp; +} nxt_diyfp_t; + + +#define nxt_diyfp(_s, _e) (nxt_diyfp_t) \ + { .significand = (_s), .exp = (_e) } +#define nxt_uint64(h, l) (((uint64_t) (h) << 32) + (l)) + + +#define NXT_DBL_SIGNIFICAND_SIZE 52 +#define NXT_DBL_EXPONENT_BIAS (0x3FF + NXT_DBL_SIGNIFICAND_SIZE) +#define NXT_DBL_EXPONENT_MIN (-NXT_DBL_EXPONENT_BIAS) +#define NXT_DBL_EXPONENT_MAX (0x7FF - NXT_DBL_EXPONENT_BIAS) +#define NXT_DBL_EXPONENT_DENORMAL (-NXT_DBL_EXPONENT_BIAS + 1) + +#define NXT_DBL_SIGNIFICAND_MASK nxt_uint64(0x000FFFFF, 0xFFFFFFFF) +#define NXT_DBL_HIDDEN_BIT nxt_uint64(0x00100000, 0x00000000) +#define NXT_DBL_EXPONENT_MASK nxt_uint64(0x7FF00000, 0x00000000) + +#define NXT_DIYFP_SIGNIFICAND_SIZE 64 + +#define NXT_SIGNIFICAND_SIZE 53 +#define NXT_SIGNIFICAND_SHIFT (NXT_DIYFP_SIGNIFICAND_SIZE \ + - NXT_DBL_SIGNIFICAND_SIZE) + +#define NXT_DECIMAL_EXPONENT_OFF 348 +#define NXT_DECIMAL_EXPONENT_MIN (-348) +#define NXT_DECIMAL_EXPONENT_MAX 340 +#define NXT_DECIMAL_EXPONENT_DIST 8 + + +nxt_inline nxt_diyfp_t +nxt_d2diyfp(double d) +{ + int biased_exp; + uint64_t significand; + nxt_diyfp_t r; + + union { + double d; + uint64_t u64; + } u; + + u.d = d; + + biased_exp = (u.u64 & NXT_DBL_EXPONENT_MASK) >> NXT_DBL_SIGNIFICAND_SIZE; + significand = u.u64 & NXT_DBL_SIGNIFICAND_MASK; + + if (biased_exp != 0) { + r.significand = significand + NXT_DBL_HIDDEN_BIT; + r.exp = biased_exp - NXT_DBL_EXPONENT_BIAS; + + } else { + r.significand = significand; + r.exp = NXT_DBL_EXPONENT_MIN + 1; + } + + return r; +} + + +nxt_inline double +nxt_diyfp2d(nxt_diyfp_t v) +{ + int exp; + uint64_t significand, biased_exp; + + union { + double d; + uint64_t u64; + } u; + + exp = v.exp; + significand = v.significand; + + while (significand > NXT_DBL_HIDDEN_BIT + NXT_DBL_SIGNIFICAND_MASK) { + significand >>= 1; + exp++; + } + + if (exp >= NXT_DBL_EXPONENT_MAX) { + return INFINITY; + } + + if (exp < NXT_DBL_EXPONENT_DENORMAL) { + return 0.0; + } + + while (exp > NXT_DBL_EXPONENT_DENORMAL + && (significand & NXT_DBL_HIDDEN_BIT) == 0) + { + significand <<= 1; + exp--; + } + + if (exp == NXT_DBL_EXPONENT_DENORMAL + && (significand & NXT_DBL_HIDDEN_BIT) == 0) + { + biased_exp = 0; + + } else { + biased_exp = (uint64_t) (exp + NXT_DBL_EXPONENT_BIAS); + } + + u.u64 = (significand & NXT_DBL_SIGNIFICAND_MASK) + | (biased_exp << NXT_DBL_SIGNIFICAND_SIZE); + + return u.d; +} + + +nxt_inline nxt_diyfp_t +nxt_diyfp_shift_left(nxt_diyfp_t v, unsigned shift) +{ + return nxt_diyfp(v.significand << shift, v.exp - shift); +} + + +nxt_inline nxt_diyfp_t +nxt_diyfp_shift_right(nxt_diyfp_t v, unsigned shift) +{ + return nxt_diyfp(v.significand >> shift, v.exp + shift); +} + + +nxt_inline nxt_diyfp_t +nxt_diyfp_sub(nxt_diyfp_t lhs, nxt_diyfp_t rhs) +{ + return nxt_diyfp(lhs.significand - rhs.significand, lhs.exp); +} + + +nxt_inline nxt_diyfp_t +nxt_diyfp_mul(nxt_diyfp_t lhs, nxt_diyfp_t rhs) +{ +#if (NXT_HAVE_UNSIGNED_INT128) + + uint64_t l, h; + nxt_uint128_t u128; + + u128 = (nxt_uint128_t) (lhs.significand) + * (nxt_uint128_t) (rhs.significand); + + h = u128 >> 64; + l = (uint64_t) u128; + + /* rounding. */ + + if (l & ((uint64_t) 1 << 63)) { + h++; + } + + return nxt_diyfp(h, lhs.exp + rhs.exp + 64); + +#else + + uint64_t a, b, c, d, ac, bc, ad, bd, tmp; + + a = lhs.significand >> 32; + b = lhs.significand & 0xffffffff; + c = rhs.significand >> 32; + d = rhs.significand & 0xffffffff; + + ac = a * c; + bc = b * c; + ad = a * d; + bd = b * d; + + tmp = (bd >> 32) + (ad & 0xffffffff) + (bc & 0xffffffff); + + /* mult_round. */ + + tmp += 1U << 31; + + return nxt_diyfp(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), + lhs.exp + rhs.exp + 64); + +#endif +} + + +nxt_inline nxt_diyfp_t +nxt_diyfp_normalize(nxt_diyfp_t v) +{ + return nxt_diyfp_shift_left(v, nxt_leading_zeros64(v.significand)); +} + + +nxt_diyfp_t nxt_cached_power_dec(int exp, int *dec_exp); +nxt_diyfp_t nxt_cached_power_bin(int exp, int *dec_exp); + + +#endif /* _NXT_DIYFP_H_INCLUDED_ */ diff -r 9322e8eab0b6 -r 0f9c060a0198 nxt/nxt_dtoa.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nxt/nxt_dtoa.c Thu Jul 19 18:11:52 2018 +0300 @@ -0,0 +1,363 @@ + +/* + * Copyright (C) Dmitry Volyntsev + * Copyright (C) NGINX, Inc. + * + * Grisu2 algorithm implementation for printing floating-point numbers based + * upon the work of Milo Yip and Doug Currie. + * + * For algorithm information, see Loitsch, Florian. "Printing + * floating-point numbers quickly and accurately with integers." ACM Sigplan + * Notices 45.6 (2010): 233-243. + * + * Copyright (C) 2015 Doug Currie + * based on dtoa_milo.h + * Copyright (C) 2014 Milo Yip + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include <nxt_auto_config.h> +#include <nxt_types.h> +#include <nxt_clang.h> +#include <nxt_string.h> +#include <nxt_diyfp.h> +#include <nxt_dtoa.h> + +#include <math.h> +#include <string.h> + + +nxt_inline void +nxt_grisu2_round(char *start, size_t len, uint64_t delta, uint64_t rest, + uint64_t ten_kappa, uint64_t wp_w) +{ + while (rest < wp_w && delta - rest >= ten_kappa + && (rest + ten_kappa < wp_w || /* closer */ + wp_w - rest > rest + ten_kappa - wp_w)) + { + start[len - 1]--; + rest += ten_kappa; + } +} + + +nxt_inline int +nxt_dec_count(uint32_t n) +{ + if (n < 10) return 1; + if (n < 100) return 2; + if (n < 1000) return 3; + if (n < 10000) return 4; + if (n < 100000) return 5; + if (n < 1000000) return 6; + if (n < 10000000) return 7; + if (n < 100000000) return 8; + if (n < 1000000000) return 9; + + return 10; +} + + +nxt_inline size_t +nxt_grisu2_gen(nxt_diyfp_t W, nxt_diyfp_t Mp, uint64_t delta, char *start, + int *dec_exp) +{ + int kappa; + char c, *p; + uint32_t p1, d; + uint64_t p2, tmp; + nxt_diyfp_t one, wp_w; + + static const uint64_t pow10[] = { + 1, + 10, + 100, + 1000, + 10000, + 100000, + 1000000, + 10000000, + 100000000, + 1000000000 + }; + + wp_w = nxt_diyfp_sub(Mp, W); + + one = nxt_diyfp((uint64_t) 1 << -Mp.exp, Mp.exp); + p1 = (uint32_t) (Mp.significand >> -one.exp); + p2 = Mp.significand & (one.significand - 1); + + p = start; + + kappa = nxt_dec_count(p1); + + while (kappa > 0) { + + switch (kappa) { + case 10: d = p1 / 1000000000; p1 %= 1000000000; break; + case 9: d = p1 / 100000000; p1 %= 100000000; break; + case 8: d = p1 / 10000000; p1 %= 10000000; break; + case 7: d = p1 / 1000000; p1 %= 1000000; break; + case 6: d = p1 / 100000; p1 %= 100000; break; + case 5: d = p1 / 10000; p1 %= 10000; break; + case 4: d = p1 / 1000; p1 %= 1000; break; + case 3: d = p1 / 100; p1 %= 100; break; + case 2: d = p1 / 10; p1 %= 10; break; + case 1: d = p1; p1 = 0; break; + default: + nxt_unreachable(); _______________________________________________ nginx-devel mailing list nginx-devel@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx-devel