diff --git a/src/modp_numtoa.c b/src/modp_numtoa.c index d77b68580a..0725e58159 100644 --- a/src/modp_numtoa.c +++ b/src/modp_numtoa.c @@ -23,6 +23,8 @@ */ static const double _pow10[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000}; +static const double _pow10r[] = {1, .1, .01, .001, .0001, .00001, .000001, + .0000001, .00000001, .000000001}; static void strreverse(char* begin, char* end) { @@ -287,6 +289,14 @@ void modp_dtoa2(double value, char* str, int prec) prec = 9; } + double smallest = _pow10r[prec]; + + if (value != 0.0 && value < smallest) { + sprintf(str, "%.*e", DBL_DECIMAL_DIG - 1, neg ? -value : value); + sn_strip_trailing_zeros(str); + return; + } + int whole = (int) value; double tmp = (value - whole) * _pow10[prec]; uint32_t frac = (uint32_t)(tmp); diff --git a/src/modp_numtoa.h b/src/modp_numtoa.h index 619a4ac767..c8c46827c8 100644 --- a/src/modp_numtoa.h +++ b/src/modp_numtoa.h @@ -91,6 +91,10 @@ void modp_dtoa(double value, char* buf, int precision); * will be switched exponential format and include as many precision digits * as needed to preserve information. * + * If a non-zero input value is less than 10^(-precision), the output format + * will be switched exponential format and include as many precision digits + * as needed to preserve information. + * * \param[in] value * \param[out] buf The allocated output buffer. Should be 32 chars or more. * \param[in] precision Number of digits to the right of the decimal point. diff --git a/testing/btest/Baseline/language.double/out b/testing/btest/Baseline/language.double/out index 8ec12b40e1..453fae924f 100644 --- a/testing/btest/Baseline/language.double/out +++ b/testing/btest/Baseline/language.double/out @@ -27,3 +27,35 @@ relational operator (PASS) relational operator (PASS) division operator (PASS) max double value = 1.7976931348623157e+308 (PASS) + +4.9999999999999999e-13 +4.9999999999999997e-12 +5.0000000000000002e-11 +5.0000000000000003e-10 +5.0000000000000001e-09 +4.9999999999999998e-08 +4.9999999999999998e-07 + +0.000005 +0.00005 +0.0005 +0.005 +0.05 +0.5 +5.0 + +1.e-13 +9.9999999999999998e-13 +9.9999999999999994e-12 +1.e-10 +1.0000000000000001e-09 +1.e-08 +9.9999999999999995e-08 + +0.000001 +0.00001 +0.0001 +0.001 +0.01 +0.1 +1.0 diff --git a/testing/btest/language/double.zeek b/testing/btest/language/double.zeek index 56ce711da2..f98abc839a 100644 --- a/testing/btest/language/double.zeek +++ b/testing/btest/language/double.zeek @@ -75,5 +75,40 @@ event zeek_init() local str1 = fmt("max double value = %.16e", d19); test_case( str1, str1 == "max double value = 1.7976931348623157e+308" ); + # Printing small numbers: default precision is 6 with values smaller than + # 10^-6 rendered in scientific notation, preserving exact floating point + # representation. + print ""; + print 0.0000000000005; + print 0.000000000005; + print 0.00000000005; + print 0.0000000005; + print 0.000000005; + print 0.00000005; + print 0.0000005; + print ""; + print 0.000005; + print 0.00005; + print 0.0005; + print 0.005; + print 0.05; + print 0.5; + print 5.0; + print ""; + print 0.0000000000001; + print 0.000000000001; + print 0.00000000001; + print 0.0000000001; + print 0.000000001; + print 0.00000001; + print 0.0000001; + print ""; + print 0.000001; + print 0.00001; + print 0.0001; + print 0.001; + print 0.01; + print 0.1; + print 1.0; }