-->

PI and accuracy of a floating-point number

2020-08-10 09:09发布

问题:

A single/double/extended-precision floating-point representation of Pi is accurate up to how many decimal places?

回答1:

#include <stdio.h>

#define E_PI 3.1415926535897932384626433832795028841971693993751058209749445923078164062

int main(int argc, char** argv)
{
    long double pild = E_PI;
    double pid = pild;
    float pif = pid;
    printf("%s\n%1.80f\n%1.80f\n%1.80Lf\n",
    "3.14159265358979323846264338327950288419716939937510582097494459230781640628620899",
    pif, pid, pild);
    return 0;
}

Results:

[quassnoi #] gcc --version
gcc (GCC) 4.3.2 20081105 (Red Hat 4.3.2-7)

[quassnoi #] ./test

3.14159265358979323846264338327950288419716939937510582097494459230781640628620899

3.14159274101257324218750000000000000000000000000000000000000000000000000000000000
        ^
3.14159265358979311599796346854418516159057617187500000000000000000000000000000000
                 ^
3.14159265358979311599796346854418516159057617187500000000000000000000000000000000
                 ^
  0000000001111111
  1234567890123456


回答2:

When I examined Quassnoi's answer it seemed suspicious to me that long double and double would end up with the same accuracy so I dug in a little. If I ran his code compiled with clang I got the same results as him. However I found out that if I specified the long double suffix and used a literal to initialize the long double it provided more precision. Here is my version of his code:

#include <stdio.h>

int main(int argc, char** argv)
{
    long double pild = 3.14159265358979323846264338327950288419716939937510582097494459230781640628620899L;
    double pid = pild;
    float pif = pid;
    printf("%s\n%1.80f\n%1.80f\n%1.80Lf\n",
        "3.14159265358979323846264338327950288419716939937510582097494459230781640628620899",
        pif, pid, pild);
    return 0;
}

And the results:

3.14159265358979323846264338327950288419716939937510582097494459230781640628620899

3.14159274101257324218750000000000000000000000000000000000000000000000000000000000
        ^
3.14159265358979311599796346854418516159057617187500000000000000000000000000000000
                 ^
3.14159265358979323851280895940618620443274267017841339111328125000000000000000000
                    ^


回答3:

6 places and 14 places.1 place is over 0 for the 3, and the last place although stored can't be considered as a precision point.

And sorry but I don't know what extended means without more context. Do you mean C#'s decimal?



回答4:

Print and count, baby, print and count. (Or read the specs.)



回答5:

Accuracy of a floating-point type is not related to PI or any specific numbers. It only depends on how many digits are stored in memory for that specific type.

In case of IEEE-754 float uses 23 bits of mantissa so it can be accurate to 23+1 bits of precision, or ~7 digits of precision in decimal. Regardless of π, e, 1.1, 9.87e9... all of them is stored with exactly 24 bits in a float. Similarly double (53 bits of mantissa) can store 15~17 decimal digits of precision.



回答6:

In the x86 floating-point unit (x87) there are instructions for loading certain floating point constants. "fldz" and "fld1" load 0.0 and 1.0 onto the stack top "st" (aka "st(0)") for example. Another is "fldpi".

All these values have a mantissa that's 64 bits long which translates into close to 20 decimal digits. The 64 bits are possible through the 80-bit tempreal floating point format used internally in the x87. The x87 can load tempreals from and store them to 10 byte memory locations as well.



回答7:

World of PI have PI to 100,000,000,000 digits, you could just print and compare. For a slightly easier to read version Joy of PI have 10,000 digits. And if you want to remember the digits youself you could try lerning the Cadaeic Cadenza poem.



回答8:

For C code, look at the definitions in <float.h>. That covers float (FLT_*), double (DBL_*) and long double (LDBL_*) definitions.



回答9:

Since there are sieve equations for binary representations of pi, one could combine variables to store pieces of the value to increase precision. The only limitation to the precision on this method is conversion from binary to decimal, but even rational numbers can run into issues with that.



回答10:

* EDIT: see this post for up to date discussion: Implementation of sinpi() and cospi() using standard C math library *

The new math.h functions __sinpi() and __cospi() fixed the problem for me for right angles like 90 degrees and such.

cos(M_PI * -90.0 / 180.0) returns 0.00000000000000006123233995736766
__cospi( -90.0 / 180.0 )      returns 0.0, as it should

/*  __sinpi(x) returns the sine of pi times x; __cospi(x) and __tanpi(x) return
the cosine and tangent, respectively.  These functions can produce a more
accurate answer than expressions of the form sin(M_PI * x) because they
avoid any loss of precision that results from rounding the result of the
multiplication M_PI * x.  They may also be significantly more efficient in
some cases because the argument reduction for these functions is easier
to compute.  Consult the man pages for edge case details.                 */
extern float __cospif(float) __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_NA);
extern double __cospi(double) __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_NA);
extern float __sinpif(float) __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_NA);
extern double __sinpi(double) __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_NA);
extern float __tanpif(float) __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_NA);
extern double __tanpi(double) __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_NA);