序章
浮動小数点演算は、多くの人にとって難解な主題と見なされています。浮動小数点はコンピュータシステムに遍在しているため、これはかなり驚くべきことです。ほとんどの小数は2進数として正確に表現されていないため、丸めが行われています。良いスタートは、すべてのコンピューター科学者が浮動小数点演算について知っておくべきことです
質問
質問1
正確な2桁の計算(お金)が必要な場合、このソリューションに頼ることはできますか?
回答1
正確な2桁が必要な場合 、答えは「いいえ 」です。phpの精度設定を使用して、たとえそうである場合でも、常に2桁のnot going to work on numbers higher than 10^6
小数を確認することはできません。
計算中に、長さが8未満の場合、精度の長さが増加する可能性があります。
質問2
そうでない場合は、このソリューションが失敗したときの明確な例を教えてください。
回答2
ini_set('precision', 8); // your precision
$a = 5.88 ; // cost of 1kg
$q = 2.49 ;// User buys 2.49 kg
$b = $a * 0.01 ; // 10% Discount only on first kg ;
echo ($a * $q) - $b;
出力
14.5824 <---- not precise 2 digits calculations even if precision is 8
質問3
どのphp.ini.precision値が、2桁の金額の計算に最適ですか?
回答3
精度とお金の計算は2つの異なるものです...財務計算または浮動小数点の長さのベースとしてPHPの精度を使用することはお勧めできません
簡単なテスト
bcmath
を使用していくつかの例を一緒に実行しないnumber_format
でください。minus
Base
$a = 342349.23;
$b = 341765.07;
Example A
ini_set('precision', 20); // set to 20
echo $a - $b, PHP_EOL;
echo floatval(round($a - $b, 2)), PHP_EOL;
echo number_format($a - $b, 2), PHP_EOL;
echo bcsub($a, $b, 2), PHP_EOL;
出力
584.15999999997438863
584.15999999999996817 <----- Round having a party
584.16
584.15 <-------- here is 15 because precision value is 20
Example B
ini_set('precision', 14); // change to 14
echo $a - $b, PHP_EOL;
echo floatval(round($a - $b, 2)), PHP_EOL;
echo number_format($a - $b, 2), PHP_EOL;
echo bcsub($a, $b, 2), PHP_EOL;
出力
584.15999999997
584.16
584.16
584.16 <-------- at 14 it changed to 16
Example C
ini_set('precision', 6); // change to 6
echo $a - $b, PHP_EOL;
echo floatval(round($a - $b, 2)), PHP_EOL;
echo number_format($a - $b, 2), PHP_EOL;
echo bcsub($a, $b, 2), PHP_EOL;
出力
584.16
584.16
584.16
584.00 <--- at 6 it changed to 00
Example D
ini_set('precision', 3); // change to 3
echo $a - $b, PHP_EOL;
echo floatval(round($a - $b, 2)), PHP_EOL;
echo number_format($a - $b, 2), PHP_EOL;
echo bcsub($a, $b, 2), PHP_EOL;
出力
584
584
584.16 <-------------------------------- They only consistent value
0.00 <--- at 3 .. everything is gone
結論
浮動小数点を忘れてcents
、後で計算し、それ100
が遅すぎる場合は単に使用するだけnumber_format
で、私には一貫しているように見えます。
アップデート
質問1:AとBが小数点以下の桁数である0..999999.99の間の数値では、精度の回避策は失敗しますか?もしそうなら、私に例を教えてください
の増分でのフォーム0
は、ループの組み合わせの可能性についてです。 私は、誰もあなたのためにそのようなテストを実行したいとは思わないでしょう。999999.99
0.01
99,999,999
9,999,999,800,000,000
浮動小数点は有限の精度の2進数であるため、設定しようとするとprecision
、精度を確保するための効果が制限されます。簡単なテストを次に示します。
ini_set('precision', 8);
$a = 0.19;
$b = 0.16;
$c = 0.01;
$d = 0.01;
$e = 0.01;
$f = 0.01;
$g = 0.01;
$h = $a + $b + $c + $d + $e + $f + $g;
echo "Total: " , $h , PHP_EOL;
$i = $h-$a;
$i = $i-$b;
$i = $i-$c;
$i = $i-$d;
$i = $i-$e;
$i = $i-$f;
$i = $i-$g;
echo $i , PHP_EOL;
出力
Total: 0.4
1.0408341E-17 <--- am sure you would expect 0.00 here ;
試す
echo round($i,2) , PHP_EOL;
echo number_format($i,2) , PHP_EOL;
出力
0
0.00 <------ still confirms number_format is most accurate to maintain 2 digit
質問2:精度の回避策が失敗した場合の見積もり/計算方法は?そのようなクレイジーなテストなしで?数学的な*、それに対する正解はありますか?計算方法は失敗するかどうか?
浮動小数点には精度の問題がありますが、数学的な解決策については、
浮動小数点計算が機能することを知る必要はありませんが、精度とAとBの範囲を知っていれば、回避策が失敗した場合

そのステートメントが何を意味するのかわからない:)