17

Can someone give me an example of a floating point number (double precision), that needs more than 16 significant decimal digits to represent it?

I have found in this thread that sometimes you need up to 17 digits, but I am not able to find an example of such a number (16 seems enough to me).

Can somebody clarify this?

phuclv
  • 37,963
  • 15
  • 156
  • 475
Ondřej Čertík
  • 780
  • 8
  • 18

5 Answers5

11

My other answer was dead wrong.

#include <stdio.h>

int
main(int argc, char *argv[])
{
    unsigned long long n = 1ULL << 53;
    unsigned long long a = 2*(n-1);
    unsigned long long b = 2*(n-2);
    printf("%llu\n%llu\n%d\n", a, b, (double)a == (double)b);
    return 0;
}

Compile and run to see:

18014398509481982
18014398509481980
0

a and b are just 2*(253-1) and 2*(253-2).

Those are 17-digit base-10 numbers. When rounded to 16 digits, they are the same. Yet a and b clearly only need 53 bits of precision to represent in base-2. So if you take a and b and cast them to double, you get your counter-example.

phuclv
  • 37,963
  • 15
  • 156
  • 475
Nemo
  • 70,042
  • 10
  • 116
  • 153
3

The correct answer is the one by Nemo above. Here I am just pasting a simple Fortran program showing an example of the two numbers, that need 17 digits of precision to print, showing, that one does need (es23.16) format to print double precision numbers, if one doesn't want to loose any precision:

program test
implicit none
integer, parameter :: dp = kind(0.d0)
real(dp) :: a, b
a = 1.8014398509481982e+16_dp
b = 1.8014398509481980e+16_dp
print *, "First we show, that we have two different 'a' and 'b':"
print *, "a == b:", a == b, "a-b:", a-b
print *, "using (es22.15)"
print "(es22.15)", a
print "(es22.15)", b
print *, "using (es23.16)"
print "(es23.16)", a
print "(es23.16)", b
end program

it prints:

First we show, that we have two different 'a' and 'b':
a == b: F a-b:   2.0000000000000000     
using (es22.15)
1.801439850948198E+16
1.801439850948198E+16
using (es23.16)
1.8014398509481982E+16
1.8014398509481980E+16
Ondřej Čertík
  • 780
  • 8
  • 18
1

I think the guy on that thread is wrong, and 16 base-10 digits are always enough to represent an IEEE double.

My attempt at a proof would go something like this:

Suppose otherwise. Then, necessarily, two distinct double-precision numbers must be represented by the same 16-significant-digit base-10 number.

But two distinct double-precision numbers must differ by at least one part in 253, which is greater than one part in 1016. And no two numbers differing by more than one part in 1016 could possibly round to the same 16-significant-digit base-10 number.

This is not completely rigorous and could be wrong. :-)

phuclv
  • 37,963
  • 15
  • 156
  • 475
Nemo
  • 70,042
  • 10
  • 116
  • 153
  • Nice argument. I am putting this as the right answer, unless somebody actually provides a counter argument (some number that doesn't work). Here is the code in Python (the formatting is not great): `In [1]: 2**(-53) Out[1]: 1.1102230246251565e-16 In [2]: 10**(-16) Out[2]: 9.9999999999999998e-17 ` – Ondřej Čertík May 25 '11 at 05:36
  • Unfortunately, I now think I am wrong... Suppose we only had three bits of mantissa. By my argument, that should correspond to one base-10 digit. But now consider 2, 4, 6, 8, 10, 12, and 14 (i.e., 2 times 1,2,3,...7). Those are clearly three-bit mantissas, but 10, 12, and 14 are all the same when rounded to one significant digit. I will try to construct a "double" counterexample later today. (Great question, btw) – Nemo May 25 '11 at 13:25
  • Indeed, your other answer nailed this down. So I put that one as the correct answer. Thanks a lot for this, I really appreciate your effort. So now it is clear, that if I want to print doubles, I do need to use `%.16e` in C, or `(es23.16)` in Fortran. – Ondřej Čertík May 26 '11 at 05:16
0

The largest continuous range of integers that can be exactly represented by a double (8-byte IEEE) is -253 to 253 (-9007199254740992. to 9007199254740992.). The numbers -253-1 and 253+1 cannot be exactly represented by a double.

Therefore, no more than 16 significant decimal digits to the left of the decimal point will exactly represent a double in the continuous range.

phuclv
  • 37,963
  • 15
  • 156
  • 475
BSalita
  • 8,420
  • 10
  • 51
  • 68
0

Dig into the single and double precision basics and wean yourself of the notion of this or that (16-17) many DECIMAL digits and start thinking in (53) BINARY digits. The necessary examples may be found here at stackoverflow if you spend some time digging.

And I fail to see how you can award a best answer to anyone giving a DECIMAL answer without qualified BINARY explanations. This stuff is straight-forward but it is not trivial.

Olof Forshell
  • 3,169
  • 22
  • 28
  • Hi Olof, thanks for your answer. I have searched through the stackoverflow very carefully, but wasn't able to find the answer to my question. Could you please point me to some examples of that? – Ondřej Čertík Aug 03 '11 at 19:07
  • [This post](http://stackoverflow.com/questions/4738768/printing-double-without-losing-precision/4851671#4851671) should provide you with some insight into why floating point values (seem to) "behave stangely" (they don't). I'll try to find some more. – Olof Forshell Aug 04 '11 at 07:59
  • [Here's another](http://stackoverflow.com/questions/4827176/how-to-distinguish-between-1-and-zero-floating-point-values/4844572#4844572) and [another](http://stackoverflow.com/questions/327020/why-are-floating-point-values-so-prolific/4164252#4164252) – Olof Forshell Aug 04 '11 at 08:04
  • @Ondrej Certik: so how did you get along with the binary angle on floating point decimals? – Olof Forshell Aug 21 '11 at 07:56
  • Thanks a lot for the pointers. In fact, I have read all these posts before asking here, because I couldn't find an example of a number that needs 17 digits. The accepted answer at this question answers this. – Ondřej Čertík Dec 08 '11 at 07:51
  • Voyager space travel? South Korean National accounting? Indonesian National accounting? Accounting programs do not store values as floating point dollars.cents (for example) instead they use cents: when the values need to be displayed they use value/100.value%100. My point is that floating point is not good for exact values unless you leave out the fraction part and, if you do, you get fewer significant digits than if you were to use integers. The US public debt (today) is 15,071,624,794,970.66 - that's 16 digits. Significant digit requirements have a way of sneaking up on and biting you :) – Olof Forshell Dec 08 '11 at 09:28