Taking a float and adding hundreds of zeros, you may get a truncated value that is just one over the desired value (bug fix) (#1388)

* Found a bug where if take some float and add many zeros, you may get a truncated value that is just one over the desired value.
This commit is contained in:
Daniel Lemire 2021-01-11 17:07:25 -05:00 committed by GitHub
parent ce1756425f
commit 7dbe4caf3f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 25 additions and 10 deletions

View File

@ -98,7 +98,20 @@ decimal parse_decimal(const char *&p) noexcept {
}
answer.decimal_point = int32_t(first_after_period - p);
}
if(answer.num_digits > 0) {
const char *preverse = p - 1;
int32_t trailing_zeros = 0;
while ((*preverse == '0') || (*preverse == '.')) {
if(*preverse == '0') { trailing_zeros++; };
--preverse;
}
answer.decimal_point += int32_t(answer.num_digits);
answer.num_digits -= uint32_t(trailing_zeros);
}
if(answer.num_digits > max_digits ) {
answer.num_digits = max_digits;
answer.truncated = true;
}
if (('e' == *p) || ('E' == *p)) {
++p;
bool neg_exp = false;
@ -118,11 +131,6 @@ decimal parse_decimal(const char *&p) noexcept {
}
answer.decimal_point += (neg_exp ? -exp_number : exp_number);
}
answer.decimal_point += answer.num_digits;
if(answer.num_digits > max_digits ) {
answer.num_digits = max_digits;
answer.truncated = true;
}
return answer;
}

View File

@ -280,6 +280,12 @@ namespace number_tests {
std::cout << std::dec;
return true;
}
bool truncated_borderline() {
std::cout << __func__ << std::endl;
std::string round_to_even = "9007199254740993.0";
for(size_t i = 0; i < 1000; i++) { round_to_even += "0"; }
return basic_test_64bit(round_to_even,9007199254740992);
}
bool specific_tests() {
std::cout << __func__ << std::endl;
@ -299,7 +305,8 @@ namespace number_tests {
}
bool run() {
return specific_tests() &&
return truncated_borderline() &&
specific_tests() &&
ground_truth() &&
small_integers() &&
powers_of_two() &&

View File

@ -119,9 +119,9 @@ bool check_float(double result, const char *buf) {
return false;
}
if (expected != result) {
fprintf(stderr, "parsed %.128e from \n", result);
fprintf(stderr, " %.32s whereas strtod gives\n", buf);
fprintf(stderr, " %.128e,", expected);
std::cerr << std::hexfloat << " parsed " << result << " from "
<< buf << " whereas strtod gives " << expected << std::endl;
std::cerr << std::defaultfloat;
return false;
}
return true;