PHP 浮点减法

PHP Float Subtract

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

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

    echo $n1 - $n2;
?>

为什么我得到的是 1.0760000000009 而不是 1.076

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

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

由于 every programmer should be aware of 的技术原因,IEEE 浮点数根本无法精确表示数字,并且在存储它们时会使用最接近的近似值(事实上,唯一可以完美存储的分数有分母是 2 的幂(1/2、1/4、1/8、1/16 等。所有其他值都是近似值)。PHP 有一个名为 "precision" 的 ini 值,它控制如何许多数字被认为是重要的 WHEN OUTPUTTING 浮点值。它默认为 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 pennies/cents 而不是 3.99 pounds/dollars),或者您可以使用 "bugnum" 库在 PHP、GMP 和 BC_Math 中可用,但它们使用起来都很棘手,并且有自己的陷阱。它们还可能占用 and/or 处理器时间。在大多数情况下,最好接受它并意识到当你处理浮点数时你并不是在处理一个精确的表示。

正如@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,但即使没有这些扩展也可以工作(但会降低性能)。