Reputation: 107
In java.lang.Math, we can see two constants:
public static final double E = 2.7182818284590452354;
public static final double PI = 3.14159265358979323846;
I'm curious why pi is accurate to 20 decimal places, and E to 19.
Upvotes: 4
Views: 319
Reputation: 5754
Adding to Vic Sun's great answer, a declaration for a double
is not the same thing as the internal representation of that double
.
The compiler will allow you to put many digits (at leaset 100) after the decimal place. If that declared number exceeds what the internal representation allows, the additional digits will be discarded.
Here's an example of a double
declaration with 40 digits in the decimal part, with every "0" at a multiple of 10 for easy counting. The internal representation of double
is 16 digits of decimal accuracy. Even though the declaration (40 digits) exceeds the storable accuracy (16), the code is still valid and the compiler is fine with it.
final double x = 1.1234567890123456789012345678901234567890;
// ^- 10 ^- 20 ^- 30 ^- 40
System.out.println("x: " + x);
Here's the output from running that, showing that the 16th decimal place (which should have been a "6") was instead rounded from "6" up to "7", and everything after that (position 17 through 40) was truncated:
x: 1.1234567890123457
This can also be seen when stepping through with a debugger: the value of x
is similarly shown to hold the value "1.1234567890123457" – again, 16 digits of decimal accuracy.
We could define a double
with 100 digits of accuracy for pi:
final double piTo100Digits = 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679;
System.out.println(piTo100Digits);
But at runtime we will end up with the same truncation (this time, to 15 digits instead of 16):
3.141592653589793
So the original question – why are the constants defined with different lengths? – is definitely not about actual numeric accuracy. They're both longer than 16 digits (E
is defined with 19 digits accuracy, PI
with 20 digits) and both will be truncated. They're copied below from java.lang.Math
in OpenJDK 17:
public static final double E = 2.7182818284590452354;
public static final double PI = 3.14159265358979323846;
Just to be sure, we can print them out from running code:
System.out.println("Math.E : " + Math.E);
System.out.println("Math.PI : " + Math.PI);
This confirms both values are truncated to 15 digits at runtime:
Math.E : 2.718281828459045
Math.PI : 3.141592653589793
Also, just because I was curious, both E
and PI
are listed in Javadoc with 15-digit accuracy, and not the 19 or 20-digit long values that appear in code:
java.lang.Math
Modifier and Type Constant Field Value
public static final double E 2.718281828459045
public static final double PI 3.141592653589793
Upvotes: 2
Reputation: 40034
It's irrelevant since the Math.E
version can't hold the precision specifed in the library. The trunc
version is missing the next 4 digits but the IEEE754 bits are identical to both.
long elib = Double.doubleToLongBits(2.7182818284590452354);
String elibbits =Long.toBinaryString(elib);
long etrunc = Double.doubleToLongBits(2.718281828459045);
String etruncbits = Long.toBinaryString(etrunc);
System.out.println(elibbits);
System.out.println(etruncbits);
System.out.println(elibbits.equals(etruncbits));
prints
100000000000101101111110000101010001011000101000101011101101001
100000000000101101111110000101010001011000101000101011101101001
true
Perhaps the author knew that beyond a certain number of decimal places that extraneous digits would be ignored.
Here is the linke to the IEEE754 Wiki page. The table says that 64
bits can hold a maximum of 15.95
digits.
Upvotes: 1