why is it different from that defined in the math.h library?
double
constant
3.14159265358979323846
is a double
. To retain long double
precision, use an L
. That will get us closer ...
See also @Eric Postpischil
// # define M_PI 3.14159265358979323846 /* pi */
# define M_PI_L 3.14159265358979323846L /* pi */
// ^
Is there a way to reproduce the one defined in the library?
Not quite.
Binary nature of floating point
OP's long double
cannot represent every decimal encoded value exactly. Instead a binary one is used of the form: some_int*2exponent. On my machine the closest to 3.14159265358979323846 is 3.14159265358979323851...
int main() {
// 3.1415926535897932384626433832795...
# define M_PI_L 3.14159265358979323846L /* pi */
long double a = M_PI_L;
printf("%.21Lf epsilon\n", LDBL_EPSILON);
printf("%.21Lf local epsilon\n", a - nextafterl(a, 0.0));
printf("%.21Lf before\n", nextafterl(a, 0.0));
printf("3.14159265358979323846L source code\n");
printf("%.21Lf M_PI_L\n", a);
printf("%.21Lf after\n", nextafterl(a, a*2));
}
Sample output (spaces added for clarity)
0.000000000000000000 108 epsilon
0.000000000000000000 217 local epsilon
3.141592653589793238 296 before
3.141592653589793238 46L source code
3.141592653589793238 513 M_PI_L
3.141592653589793238 730 after
My manual says the type long double extends the precision up to 24 digits. Shouldn't be enough to represent that number?
"... up to 24 digits" may be misleading. Recall floating point numbers are overwhelmingly encoded as an integer times a power of 2. Thus the precision is a binary one. Depending on the region of FP values, the corresponding decimal precision wobbles between LDBL_DIG
and LDBL_DECIMAL_DIG
which is 18, 21 on my machine. I would expect the same with OP.
@DarkAtom idea is good. To typically get the machine's best machine pi :
// Perform this once
const long double pi = acosl(-1.0L);
An alternative is to specify with lots of digits, more than expected on any target.
// 50 digit pi 1 2345678901234567890123456789012345678901234567890
const long double pi = 3.1415926535897932384626433832795028841971693993751L;