介绍
许多人认为浮点运算是一门深奥的学科。这是相当令人惊讶的,因为浮点在计算机系统中无处不在。大多数小数没有作为二进制分数的精确表示,因此需要进行一些舍入。一个好的开始是每个计算机科学家都应该知道的关于浮点运算的知识
问题
问题 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 值最适合两位数,金钱计算?
答案 3
精度和金钱计算是两个不同的东西......使用 PHP 精度作为财务计算或浮点长度的基础并不是一个好主意
简单测试
Lest Run some example together using 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:对于 0..999999.99 之间的数字,精确解决方法是否会失败,其中 A 和 B 是带小数位的数字?如果是这样,请给我一个例子
增加的形式是0
关于您的循环的组合可能性, 我真的认为没有人愿意为您运行这样的测试。999999.99
0.01
99,999,999
9,999,999,800,000,000
由于浮点数是具有有限精度的二进制数,因此尝试设置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 的范围,当变通方法失败时
不知道那句话是什么意思:)