-1

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.

hanshenrik
  • 19,904
  • 4
  • 43
  • 89
  • 1
    Assuming that you mean `binary64` (IEEE-754 also offers `decimal64`)? You're already losing "accuracy" by representing your binary floating point in decimal. The most accurate approximation that fits in a binary-64 floating point number would probably be best represented as its bits, not a decimal conversion. – spender May 24 '22 at 14:59
  • Additionally, [Wikipedia states](https://en.wikipedia.org/wiki/Double-precision_floating-point_format#IEEE_754_double-precision_binary_floating-point_format:_binary64) "The 53-bit significand precision gives from 15 to 17 significant decimal digits precision", so whatever value you quoted above (which by my count is ~49 significant digits) will be significantly truncated when stored in a binary64 fp num. – spender May 24 '22 at 17:12
  • 3
    @spender: No accuracy is lost by representing any binary floating-point number in decimal unless you do not use enough digits or do it wrong. Wikipedia’s characterization of the precision as “15 to 17 significant decimal digits” is [nonsensical and wrong](https://stackoverflow.com/a/61614323/298225). Further, good C implementations do not “truncate” decimal numerals when converting them to floating-point; they perform what IEEE-754 calls a “correctly rounded” conversion. – Eric Postpischil May 24 '22 at 20:55
  • Even IEEE-754 does not oblige using _all_ significant decimal digits. IIRC, the _minimum_ number of significant decimal digits is +3 the number needed to round-trip all _binary64_ to text to _binary64_ or 17 + 3. IAC, the first 17 digits of 3.1415926535897931159979... will round to the same _binary64_ as using more than 17 digits. Other select text values may round differently when using only 20 digits rather than 21+. But then those text values are near half-way between two _binary64_ values. – chux - Reinstate Monica May 30 '22 at 15:41

2 Answers2

3

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.

Footnote

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 Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • Detail: base 10 or 16: "For **decimal** floating constants, ..., the result is either the nearest representable value, or the larger or smaller representable value immediately adjacent to the nearest representable value, chosen in an **implementation-defined manner**. For **hexadecimal** floating constants ..., the result is **correctly rounded**. – chux - Reinstate Monica May 30 '22 at 15:51
  • fwiw i checked, you're right, 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, and 3 is more than 1, which means you're right :) ) – hanshenrik Jul 07 '22 at 20:37
0

@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:

  • warning, takes like 7 minutes to run on my laptop (i7-8565U, a 2018 mid-range laptop cpu)
  • warning: not peer-reviewed, might be buggy
  • Warning: i assumed 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
hanshenrik
  • 19,904
  • 4
  • 43
  • 89