From c5adf9e4a59c429e3c02a078d033d5fda4c6a3ba Mon Sep 17 00:00:00 2001 From: Daniel Lemire Date: Mon, 11 Jan 2021 11:22:00 -0500 Subject: [PATCH] Fix truncate flag. --- include/fast_float/ascii_number.h | 26 +++++++++++++++++++++----- tests/basictest.cpp | 10 ++++++---- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 75432a3..e8d12ee 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -249,6 +249,27 @@ fastfloat_really_inline decimal parse_decimal(const char *p, const char *pend) n } answer.decimal_point = int32_t(first_after_period - p); } + // We want num_digits to be the number of significant digits, excluding + // leading *and* trailing zeros! Otherwise the truncated flag later is + // going to be misleading. + if(answer.num_digits > 0) { + // We potentially need the answer.num_digits > 0 guard because we + // prune leading zeros. So with answer.num_digits > 0, we know that + // we have at least one non-zero digit. + const char *preverse = p - 1; + int32_t trailing_zeros = 0; + while ((*preverse == '0') || (*preverse == '.')) { + if(*preverse == '0') { trailing_zeros++; }; + --preverse; + } + answer.decimal_point += trailing_zeros; + answer.num_digits -= uint32_t(trailing_zeros); + answer.decimal_point += int32_t(answer.num_digits); + } + if(answer.num_digits > max_digits) { + answer.truncated = true; + answer.num_digits = max_digits; + } if ((p != pend) && (('e' == *p) || ('E' == *p))) { ++p; bool neg_exp = false; @@ -268,11 +289,6 @@ fastfloat_really_inline decimal parse_decimal(const char *p, const char *pend) n } answer.decimal_point += (neg_exp ? -exp_number : exp_number); } - answer.decimal_point += int32_t(answer.num_digits); - if(answer.num_digits > max_digits) { - answer.truncated = true; - answer.num_digits = max_digits; - } // In very rare cases, we may have fewer than 19 digits, we want to be able to reliably // assume that all digits up to max_digit_without_overflow have been initialized. for(uint32_t i = answer.num_digits; i < max_digit_without_overflow; i++) { answer.digits[i] = 0; } diff --git a/tests/basictest.cpp b/tests/basictest.cpp index 100815b..66ba9c6 100644 --- a/tests/basictest.cpp +++ b/tests/basictest.cpp @@ -294,10 +294,8 @@ TEST_CASE("64bit.inf") { } TEST_CASE("64bit.general") { - verify("1.1754941406275178592461758986628081843312458647327962400313859427181746759860647699724722770042717456817626953125", 0x1.2ced2f1aa2833p+0); - verify(append_zeros("1.1754941406275178592461758986628081843312458647327962400313859427181746759860647699724722770042717456817626953125",655), 0x1.2ced2f1aa2833p+0); - verify(append_zeros("1.1754941406275178592461758986628081843312458647327962400313859427181746759860647699724722770042717456817626953125",656), 0x1.2ced2f1aa2833p+0); - verify(append_zeros("1.1754941406275178592461758986628081843312458647327962400313859427181746759860647699724722770042717456817626953125",1000), 0x1.2ced2f1aa2833p+0); + verify("9007199254740993.0", 0x1p+53); + verify(append_zeros("9007199254740993.0",1000), 0x1p+53); verify("10000000000000000000", 0x1.158e460913dp+63); verify("10000000000000000000000000000001000000000000", 0x1.cb2d6f618c879p+142); verify("10000000000000000000000000000000000000000001", 0x1.cb2d6f618c879p+142); @@ -369,9 +367,13 @@ TEST_CASE("32bit.inf") { TEST_CASE("32bit.general") { verify("1.1754941406275178592461758986628081843312458647327962400313859427181746759860647699724722770042717456817626953125", 0x1.2ced3p+0f); + verify("1.1754941406275178592461758986628081843312458647327962400313859427181746759860647699724722770042717456817626953125e-38", 0x1.fffff8p-127f); verify(append_zeros("1.1754941406275178592461758986628081843312458647327962400313859427181746759860647699724722770042717456817626953125",655), 0x1.2ced3p+0f); verify(append_zeros("1.1754941406275178592461758986628081843312458647327962400313859427181746759860647699724722770042717456817626953125",656), 0x1.2ced3p+0f); verify(append_zeros("1.1754941406275178592461758986628081843312458647327962400313859427181746759860647699724722770042717456817626953125",1000), 0x1.2ced3p+0f); + verify(append_zeros("1.1754941406275178592461758986628081843312458647327962400313859427181746759860647699724722770042717456817626953125",655) + "e-38", 0x1.fffff8p-127f); + verify(append_zeros("1.1754941406275178592461758986628081843312458647327962400313859427181746759860647699724722770042717456817626953125",656) + "e-38", 0x1.fffff8p-127f); + verify(append_zeros("1.1754941406275178592461758986628081843312458647327962400313859427181746759860647699724722770042717456817626953125",1000) + "e-38", 0x1.fffff8p-127f); verify32(1.00000006e+09f); verify32(1.4012984643e-45f); verify32(1.1754942107e-38f);