what is the most accurate approximation of pi possible in IEEE-754 float64?
fwiw it seems both Javascript and PHP use 3.141592653589793115997963468544185161590576171875
, which might be the answer, i don't know.
what is the most accurate approximation of pi possible in IEEE-754 float64?
fwiw it seems both Javascript and PHP use 3.141592653589793115997963468544185161590576171875
, which might be the answer, i don't know.
Yes, 3.141592653589793115997963468544185161590576171875 is the IEEE-754 binary641 number closest to π. It can also be written as a hexadecimal floating-point constant, 0x1.921fb54442d18p1
. (I keep 0x3.243f6a8885a308d313198a2e03707344ap0L
on hand to have the value for wider formats as well.) The C standard requires C implementations that use a base-two floating-point format to correctly round hexadecimal floating-point constants, and it does not require that for decimal floating-point constants, so you may be more likely to get a correct result when you use the hexadecimal form.
1 IEEE-754 2008 uses “binary64” for the standard 64-bit base-two format. It is also called “double precision.” Some programming languages might call it float64
or Float64
.
@Eric is correct, IEEE-754-binary64 pi is approximately 0.0000000000000001 lower than real pi, and the next possible increment to IEEE-754-binary64 is approximately 0.0000000000000003 higher than real pi, that's the same number of zeroes for both, 16 zeroes, and 3 is more than 1, which means Eric+Javascript+PHP are all right. PHP test code to prove it:
0.000000000000000000000001
is the lowest increment that actually makes any difference. if i'm wrong in this assumption, setting an even lower increment might reveal a different number! (i don't have enough cpu+patience to comfortably test any lower increments..)#!/usr/bin/env php
<?php
declare(strict_types=1);
function s($x) {
$ret = number_format($x, bcscale(), '.', '');
if(false!==strpos($ret, '.')) {
$ret = rtrim($ret, '0');
if(substr($ret, -1)==='.') {
$ret = substr($ret, 0, -1);
}
}
return $ret;
}
bcscale(100);
$realPi = "3.141592653589793238462";
$IEEE64Pi = "3.141592653589793115997";
$nextPossibleIncrement = "3.141592653589793560087";// $nextPossibleIncrement = "3.141592653589793560087173318606801331043243408203125"
$testIncrement = "0.000000000000000000000001";
// var_dump(bcsub($realPi, $IEEE64Pi));die(); // IEEE64Pi this much LOWER than realPi: 0.000000000000000122465
// var_dump(bcsub($realPi, $nextPossibleIncrement));die(); // nextPossibleIncrement this much HIGHER than realPi: 0.000000000000000321625
$test = $IEEE64Pi;
for(;;){
$d1 = (float)$test;
$new = bcadd($test, $testIncrement);
$d2 = (float)$new;
if($d1 !== $d2){
echo "Error: $test != $new\n";
echo "d1: ".s($d1)."\n";
echo "d2: ".s($d2)."\n";
break;
}
$test = $new;
//echo ".";
}
output:
$ time php test.php
Error: 3.1415926535897933380425680000000000000000000000000000000000000000000000000000000000000000000000000000 != 3.1415926535897933380425690000000000000000000000000000000000000000000000000000000000000000000000000000
d1: 3.141592653589793115997963468544185161590576171875
d2: 3.141592653589793560087173318606801331043243408203125
real 6m33.130s
user 6m13.593s
sys 0m0.421s