6 ms·
Yes, thank you for this. I just ran it with the floor() function actually called and it did give 56.000000. I didn't think to check the precision. Rookie mistak
by jacobmartin 4y ago
Yes, thank you for this. I just ran it with the floor() function actually called and it did give 56.000000. I didn't think to check the precision. Rookie mistake!
- kazinator 4y agoThus, if you have a minute, try "%.20f" instead of %f. :) Or, how about this: #include <stdio.h> int main(void) { for (int prec = 0; prec < 25; prec++) { printf("%.*f\n", prec, 57.0 / 100.0 * 100.0); } return 0; } Output: 57 57.0 57.00 57.000 57.0000 57.00000 57.000000 57.0000000 57.00000000 57.000000000 57.0000000000 57.00000000000 57.000000000000 57.0000000000000 56.99999999999999 56.999999999999993 56.9999999999999929 56.99999999999999289 56.999999999999992895 56.9999999999999928946 56.99999999999999289457 56.999999999999992894573 56.9999999999999928945726 56.99999999999999289457264 56.999999999999992894572642 The 64 bit double will store 15 decimal digits reliably. That is to say, if you have a decimal figure with 15 significant digits, which is in range of the type (and not mapping to a denormal value close to zero and whatnot), all 15 digits are representable and can be recovered. In the reverse direction, you need about 17 decimal digits in order to capture an 64 bit double as decimal text such that the exact value can be recovered from the decimal text. Thus in the above loop's output, once we are past 17 digits (including the 56 before the decimal point), we are no longer seeing any new data, just a continuation of the fraction. And, notice how the last value that is still 57.000.... is exactly 15 digits wide. The next row is 16 digits, and that's where we now have 56.9999.... but 16 digits isn't quite enough to capture the value. I believe the next row gets us that: the ...99929. If we use that as a constant, any digits after that make no difference. Programming languages which, by default, print floating-point values to 15 digits will show the nice result .1 + .2 = .3. This is what I did in TXR Lisp. 1> *print-flo-precision* 15 2> (+ .1 .2) 0.3 3> (set *print-flo-precision* 16) 16 4> (+ .1 .2) 0.3 5> (set *print-flo-precision* 17) 17 6> (+ .1 .2) 0.30000000000000004 We can see there is no value difference in digits beyond 17: 7> (eq 0.30000000000000004 0.300000000000000049) t 8> (eq 0.30000000000000004 0.300000000000000040) t To get different value (different floating-point bit pattern), we need a difference in the 17th digit. And not just a single increment: 9> (eq 0.30000000000000004 0.30000000000000003) t 10> (eq 0.30000000000000004 0.30000000000000002) t The last digit being 3 and 2 is still mapping to the same value. When we make it 1, we start getting a different float: 11> (eq 0.30000000000000004 0.30000000000000001) nil