【问题标题】:PHP Float Subtract [duplicate]PHP浮点减法[重复]
【发布时间】:2018-02-07 09:18:18
【问题描述】:

我有这个简单的减法代码:

<?php
    $n1 = 257931.076;
    $n2 = 257930;

    echo $n1 - $n2;
?>

为什么我得到1.0760000000009 而不是1.076

0000000009 是从哪里来的?我需要精确的结果,我不想使用round()number_format(),因为有时我的十进制数超过3,例如: 12345.678912,有人知道吗?

我尝试过使用round()number_format(),但它只用于固定小数点,而不是动态的

【问题讨论】:

  • reading this开始如果你想知道0000000009是从哪里来的......了解浮点数学的工作原理,你就会获得智慧
  • 尝试使用number_format($variable,2,",",".");
  • 然后解释为什么echo round($n1 - $n2, 10); 对你想要的不够精确;只有这样(如果你绝对必须有绝对的精度,因为有人的生命依赖于它)考虑gmp的开销
  • @faid 那会很糟糕!只需像往常一样在内部进行所有计算,然后将最终结果四舍五入以输出。做任何其他事情都只是一种黑客行为。
  • 如果我给你一张包含我计算 1/3 的结果的纸,并要求你将它乘以 3,除非我给你一张无限长的纸,否则你永远不会得到 1。这是同样的问题,但在 base 2

标签: php numbers php-5.6


【解决方案1】:

正如@GordonM 完美解释的那样,使用浮点值时您不能期望得到准确的结果。

您可以使用 brick/math 等库对任意大小的十进制数执行精确计算:

use Brick\Math\BigDecimal;

$n1 = BigDecimal::of('257931.076'); // pass the number as a string to retain precision!
$n2 = 257930;

echo $n1->minus($n2); // 1.076

该库在可用时在内部使用 GMP 或 BCMath,但在没有这些扩展的情况下也可以工作(但会降低性能)。

【讨论】:

    【解决方案2】:

    由于every programmer should be aware of 的技术原因,IEEE 浮点数根本无法精确表示数字,并且在存储它们时将使用最接近的近似值(事实上,唯一可以完美存储的分数的分母是2(1/2、1/4、1/8、1/16 等。所有其他值都是近似值)。PHP 有一个名为“precision”的 ini 值,它控制有多少位被认为是有效的输出时 浮点值。默认为 14,之后的所有数字都隐藏。

    但是,存储的实际值可能会尝试使用比这更多的位数来逼近所需值。如果您更改精度,您将看到实际存储的内容。

    php > $test = 0.1;
    php > var_dump ($test);
    php shell code:1:
    double(0.1)
    php > ini_set("precision", 100);
    php > var_dump ($test);
    php shell code:1:
    double(0.1000000000000000055511151231257827021181583404541015625)
    php > var_dump (0.25);
    php shell code:1:
    double(0.25)
    php > var_dump (0.4);
    php shell code:1:
    double(0.40000000000000002220446049250313080847263336181640625)
    

    你实际上能做些什么呢?没什么大不了的,这只是浮点如何工作的结果。如果您需要精确的值(例如,在处理金额时,将 3.99 存储为 399 便士/美分而不是 3.99 英镑/美元),您可以尽量避免使用浮点数,或者您可以使用PHP、GMP 和 BC_Math,但这些都很难使用,并且有自己的陷阱集。它们也可能在存储和/或处理器时间上很困难。在大多数情况下,最好只是忍受它,并注意当你处理浮点时,你不是在处理精确的表示。

    【讨论】:

      猜你喜欢
      • 2019-03-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-14
      • 2013-11-22
      相关资源
      最近更新 更多