Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is java.lang.Math.PI equal to GCC's M_PI?

I am coding several reference algorithms in both Java and C/C++. Some of these algorithms use π. I would like for the two implementations of each algorithm to produce identical results, without rounding differently. One way to do this that has worked consistently so far is to use a custom-defined pi constant which is exactly the same in both languages, such as 3.14159. However, it strikes me as silly to define pi when there are already high-precision constants defined in both the Java and GCC libraries.

I've spent some time writing quick test programs, looking at documentation for each library, and reading up on floating-point types. But I haven't been able to convince myself that java.lang.Math.PI (or java.lang.StrictMath.PI) is, or is not, equal to M_PI in math.h.

GCC 3.4.4 (cygwin) math.h contains:

#define M_PI            3.14159265358979323846
                                         ^^^^^

but this

printf("%.20f", M_PI);

produces

3.14159265358979311600
                 ^^^^^

which suggests that the last 5 digits cannot be trusted.

Meanwhile, Javadocs say that java.lang.Math.PI is:

The double value that is closer than any other to pi, the ratio of the circumference of a circle to its diameter.

and

public static final double PI  3.141592653589793d

which omits the questionable last five digits from the constant.

System.out.printf("%.20f\n", Math.PI);

produces

3.14159265358979300000
                 ^^^^^

If you have some expertise in floating-point data types, can you convince me that these library constants are exactly equal? Or that they are definitely not equal?

like image 459
system PAUSE Avatar asked May 05 '09 15:05

system PAUSE


2 Answers

Note the following.

The two numbers are the same to 16 decimal places. That's almost 48 bits which are the same.

In an IEEE 64-bit floating-point number, that's all the bits there are that aren't signs or exponents.

The #define M_PI has 21 digits; that's about 63 bits of precision, which is good for an IEEE 80-bit floating-point value.

What I think you're seeing is ordinary truncation of the bits in the M_PI value.

like image 167
S.Lott Avatar answered Sep 19 '22 19:09

S.Lott


What you want to do is print out the raw bit pattern for the PI values and compare them.

In Java use the http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Double.html#doubleToRawLongBits(double) method to get the long value that you should print as binary.

Java 5 gives:

  • PI is 3.141592653589793
  • Raw bits is 4614256656552045848
  • Binary is 100000000001001001000011111101101010100010001000010110100011000

In C, you can do double pi = M_PI; printf("%lld\n", pi); to obtain the same 64bit integer: 4614256656552045848 (thanks Bruno).

like image 21
JeeBee Avatar answered Sep 22 '22 19:09

JeeBee