+6  A: 

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).

JeeBee
In C, you can do double pi = M_PI; printf("%lld\n", pi); to obtain the same 64bit integer: 4614256656552045848
Bruno De Fraine
Thanks Bruno, that pretty much answers the original question.
JeeBee
A: 

No, they aren't equal, they have different presentation in memory.

In general when you want to compare 2 floating point values you mustn't use == (and if so you can't operate with termin 'equals'). You should use comparison with epsilon.

double eps = 0.0000001;
if (Math.abs (Java_PI - Another_Pi) <= eps)
  System.out.println ("equals");
Roman
+1  A: 

a double only has like 52 bits of signficand so i think that only gives you around 15 base 10 digits which would explain why you have 5 zeroes when you ask for 20 digits.

drscroogemcduck
+10  A: 

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.

S.Lott
+1 Ran into exactly this problem when making extrememly precision time delta measurements over a large period of time. 15 digits is all you get with 64-bit double.
basszero
+2  A: 

It would be very difficult to compute the same value, even if the starting values are the same.

Floating point computation results are sometime different from an architecture to another (think x86/PowerPC for example), from a compiler to another (think GCC/MS C++) and even with the same compiler, but different compilation options. Not always, but sometimes (usually when rounding). Usually just enough for the problem to go unnoticed until too late (think after many many iterations, and many many rounding differences)

This make it quite difficult for cross-platform multi-player games that compute each iteration of the gamestate synchronously (each node only receives the input, not the actual data structures).

Therefore if even in the same language (C/C++) results can be different, from a Java VM to a native host it may also be different.

Update:

I cannot find the source I read, but I found a paper by Sun on the matter.

Like you answered yourself, java.lang.Math.PI and GCC’s M_PI can be managed to have the same value. The devil hides in the usage of these values. IEEE doesn't specify the output of math functions (sin, cos, exp, ...). Therefore it's the output of the computation that isn't necessarily the same.

Steve Schnepp
Perhaps this is a true problem in the general case, but not here. As noted in the question, "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."
system PAUSE
Added a reference link.
Steve Schnepp
+1  A: 
system PAUSE
+2  A: 

You can use BigDecimal for more accuracy like:

private static final BigDecimal PI = new BigDecimal(
"3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679" +
    "8214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196" +
    "4428810975665933446128475648233786783165271201909145648566923460348610454326648213393607260249141273" +
    "7245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094" +
    "3305727036575959195309218611738193261179310511854807446237996274956735188575272489122793818301194912" +
    "9833673362440656643086021394946395224737190702179860943702770539217176293176752384674818467669405132" +
    "0005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235" +
    "4201995611212902196086403441815981362977477130996051870721134999999837297804995105973173281609631859" +
    "5024459455346908302642522308253344685035261931188171010003137838752886587533208381420617177669147303" +
    "5982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989" +
    "3809525720106548586327886593615338182796823030195203530185296899577362259941389124972177528347913151" +
    "5574857242454150695950829533116861727855889075098381754637464939319255060400927701671139009848824012" +
    "8583616035637076601047101819429555961989467678374494482553797747268471040475346462080466842590694912" +
    "9331367702898915210475216205696602405803815019351125338243003558764024749647326391419927260426992279" +
    "6782354781636009341721641219924586315030286182974555706749838505494588586926995690927210797509302955" +
    "3211653449872027559602364806654991198818347977535663698074265425278625518184175746728909777727938000" +
    "8164706001614524919217321721477235014144197356854816136115735255213347574184946843852332390739414333" +
    "4547762416862518983569485562099219222184272550254256887671790494601653466804988627232791786085784383" +
    "8279679766814541009538837863609506800642251252051173929848960841284886269456042419652850222106611863" +
    "0674427862203919494504712371378696095636437191728746776465757396241389086583264599581339047802759009" +
    "9465764078951269468398352595709825822620522489407726719478268482601476990902640136394437455305068203" +
    "4962524517493996514314298091906592509372216964615157098583874105978859597729754989301617539284681382" +
    "6868386894277415599185592524595395943104997252468084598727364469584865383673622262609912460805124388" +
    "4390451244136549762780797715691435997700129616089441694868555848406353422072225828488648158456028506" +
    "0168427394522674676788952521385225499546667278239864565961163548862305774564980355936345681743241125"
);

public static void main(String... args) throws InterruptedException {
    System.out.println("PI to " + PI.scale() + " digits is " + PI);
    System.out.println("PI^2 to " + PI.scale() + " digits is " + 
            PI.multiply(PI).setScale(PI.scale(), BigDecimal.ROUND_HALF_UP));
}
Peter Lawrey
Um, thanks. And for GCC?
system PAUSE
A: 

Brings back memories of having to get a value for pi in fortran.

Since there were no libraries of constants, I either used 4*atan(1.) or acos(-1.).