Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do I need 17 significant digits (and not 16) to represent a double?

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?

like image 849
Ondřej Čertík Avatar asked May 25 '11 00:05

Ondřej Čertík


People also ask

How many significant digits does a double have?

Double values have between 15 and 18 digits of precision, with most double values having at least 16 significant digits. Long double has a minimum precision of 15, 18, or 33 significant digits depending on how many bytes it occupies.

What is the range of double precision?

The double precision type has a range of around 1E-307 to 1E+308 with a precision of at least 15 digits. Values that are too large or too small will cause an error. Rounding might take place if the precision of an input number is too high.

How to calculate double precision floating point?

Short answer: the max value for a double-precision value (assuming IEEE 754 floating-point) is exactly 2^1024 * (1 - 2^-53). For a single-precision value it's 2^128 * (1 - 2^-24).


2 Answers

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.

like image 72
Nemo Avatar answered Oct 17 '22 08:10

Nemo


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
like image 23
Ondřej Čertík Avatar answered Oct 17 '22 07:10

Ondřej Čertík