Can you give to me a 16 digits (or more) decimal number that converted in double precision floating point round correctly only at 15th?
Such numbers are not rare so easy enough to try various strings limited to the range of interest.
Over a wide range of 16 digit decimal text values, about 10% failed. All failures began with a leading digit of '4'
or more - not surprising.
// Although a C++ post, below is some C code
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void form_text_number(char *buf, int significant_digits, int min_expo, int max_expo) {
unsigned i = 0;
buf[i++] = (char) (rand() % 9 + '1');
buf[i++] = '.';
for (int sd = 1; sd < significant_digits; sd++) {
buf[i++] = (char) (rand() % 10 + '0');
}
sprintf(buf + i, "e%+03d", rand() % (max_expo - min_expo + 1) + min_expo);
}
bool round_trip_text_double_text(const char *s, int significant_digits) {
double d = atof(s);
char buf[significant_digits + 10];
sprintf(buf, "%.*e", significant_digits - 1, d);
if (strcmp(s, buf)) {
printf("Round trip failed \"%s\" %.*e \"%s\"\n", s, significant_digits - 1 + 3,d, buf);
return false;
}
return true;
}
Test code
void test_sig(unsigned n, int significant_digits, int min_expo, int max_expo) {
printf("Sig digits %2d: ", significant_digits);
while (n-- > 0) {
char buf[100];
form_text_number(buf, significant_digits, min_expo, max_expo);
if (!round_trip_text_double_text(buf, significant_digits)) {
return;
}
}
printf("None Failed\n");
}
int main(void) {
test_sig(10000, 16, -300, 300);
test_sig(10000, 16, -1, -1);
test_sig(1000000, 15, -300, 300);
test_sig(1000000, 15, -1, -1);
return 0;
}
Output
Sig digits 16: Round trip failed "8.995597974696435e+110" 8.995597974696434373e+110 "8.995597974696434e+110"
Sig digits 16: Round trip failed "6.654469376627144e-01" 6.654469376627144550e-01 "6.654469376627145e-01"
Sig digits 15: None Failed
Sig digits 15: None Failed
Note: When the double
was printed to 3 extra digits for many failed strings, those 3 digits were in the range 445 to 555.