[njs] Fixed Number.toString().
Dmitry Volyntsev
xeioex at nginx.com
Thu Jul 19 15:12:57 UTC 2018
details: http://hg.nginx.org/njs/rev/0f9c060a0198
branches:
changeset: 561:0f9c060a0198
user: Dmitry Volyntsev <xeioex at 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();
More information about the nginx-devel
mailing list