Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
340 views
in Technique[技术] by (71.8m points)

c - Decimal Precision Lost after 15th Digit - Bad PI

Attempting to print more than 15 decimal digits of PI result in incorrect decimals printing after the 15th decimal. This despite the 30 correct decimal values being assigned and despite using long double to hold the value. The following test case clearly shows the error.

This was unexpected. If there would be any error in the digits, I would not expect to see any error until the 25th digit after exhausting the IEEE-754 significand. What rule is in play here that might explain by I can't print back the same 30 digits I just assigned to sPI below. This also affects the ability to print the representations of M_PI contained in math.h.

#include <stdio.h>

int
main (void) {

    // static PI approximation (glibc man 1.17)
    long double sPI = 3.14159265358979323846264338327;
    char strPI[]   = "3.14159265358979323846264338327";

    printf ("
 %s (strPI - string - correct)
", strPI);
    printf (" %.29Lf (sPI - long double - INCORRECT)

", sPI);

    return (0);
}

output:

3.14159265358979323846264338327 (strPI - string - correct)
3.14159265358979311599796346854 (sPI - long double - INCORRECT)
                 ^^^^^^^^^^^^^^

Presumably, this decimal error would apply to any decimal number with greater than 16 decimal precision. When printed as a string, PI prints fine (obviously), but when printed as a double -- the decimal precision breaks down after the 15th decimal. What is causing that?

Very interesting, as suggested adding an L at the end of the floating point literal did help:

 3.14159265358979323846264338327 (strPI - string - correct)
 3.14159265358979323851280895941 (sPI - long double - INCORRECT)

That provided 3 additional decimals of precision. For clarity, this was run on Linux 3.14.1 kernel, gcc 4.8.2 on an old AMD Phenom X4 9850. (AMD Turion Based Laptop & Intel P4 gives same result)

Attempting with quadmath.h and __float128 type assigned to sPI, the results were the same as for the long double. A few more digits were available, but precision still broke down on the 19th digit:

3.14159265358979323846264338327 (strPI - string - correct)
3.1415926535897932385128089594061862 (sPI - long double - INCORRECT)
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You are not storing the 'long double' value into the variable, but the default double instead. The compiler reads the floating point value, stores it as a default type, and only casts it to long double "afterwards". You can see this when you compare its value to a "normally" assigned double.

To hint the compiler to store the constant as a long double, add the modifier suffix L or l at the end of the floating point constant.

Example:

#include <stdio.h>

int main (void)
{
    // static PI approximation (glibc man 1.17)
    double sPI_d     = 3.14159265358979323846264338327;
    long double sPI  = 3.14159265358979323846264338327;
    long double sPI_L= 3.14159265358979323846264338327L;
    char strPI[]     ="3.14159265358979323846264338327";

    printf ("
 %s (strPI - string - correct)
", strPI);
    printf (" %.29f (sPI - double)
", sPI_d);
    printf (" %.29Lf (sPI - long double - INCORRECT)
", sPI);
    printf (" %.29Lf (sPI - long double - BETTER)
", sPI_L);

    return 0;
}

Output:

 3.14159265358979323846264338327 (strPI - string - correct)
 3.14159265358979311599796346854 (sPI - double)
 3.14159265358979311599796346854 (sPI - long double - INCORRECT)
 3.14159265358979323851280895941 (sPI - long double - BETTER)

See also What is the precision of long double in C++? -- you cannot expect more than around 18 significant digits for a long double.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...