2
$a     = 100;
$b     = 3;
$test1 = $a/ $b;
$test2 = 33.333333333333;  // $test2 == $test1

var_dump(($test1 * $b));   // float(100)
var_dump(($test2 * $b));   // float(99.999999999999)

对此有何解释?

4

3 回答 3

5

100/3结果33.3-repeating

没有小数点值会显示它。在数学中,这样的数字通常由重复值上方的一个小点表示。(虽然我不知道如何在这个代码框中显示)。

请参阅此wiki 文章以了解它们在各个地方的表示方式以及我在此处给出的更详细的解释。

但是,这里的文章是摘要的片段:

在算术中,重复小数是表示有理数的一种方式。因此,如果一个数字的十进制表示在某个点变成周期性的,即如果存在无限重复的某些有限的数字序列,则称为重复小数(或循环小数)。例如,1/3 = 0.3333333… 或 0.3 的十进制表示(称为“0.3 重复”或“0.3 重复”)在小数点后变为周期性,无限重复个位数序列“3”。一个稍微复杂一点的例子是 3227/555 = 5.8144144144...,其中十进制表示在小数点后的第二个数字处变为周期性,无限地重复数字序列“144”。

现在,这是您问题的症结所在,但也要记住(正如其他两个答案所指出的那样),浮点数在计算和比较方面非常不准确。快速搜索该站点会发现一小群人对浮点的内部表示存在问题 - 主要是在进行比较时导致意外行为。

仔细阅读关于浮点数据类型的 PHP 警告- 我再次在这里复制了重要的部分:

此外,可以精确表示为以 10 为底的浮点数的有理数,如 0.1 或 0.7,没有精确表示为以 2 为底的浮点数,无论尾数大小如何,它都在内部使用。因此,它们不能被转换成它们内部的二进制对应物,而不会有小的精度损失。这可能会导致令人困惑的结果:例如, floor((0.1+0.7)*10) 通常会返回 7 而不是预期的 8,因为内部表示将类似于 7.9999999999999991118...。

于 2012-09-28T07:18:54.383 回答
1

并非所有floats 都可以由处理器精确表示。$a/$b是其中之一。

所以,$test1 != $test2是真的。

于 2012-09-28T07:20:22.683 回答
1

来自PHP的信息

警告

浮点精度

浮点数的精度有限。尽管取决于系统,但 PHP 通常使用 IEEE 754 双精度格式,由于在 1.11e-16 的数量级四舍五入,这将给出最大的相对误差。非初等算术运算可能会产生更大的误差,当然,当多个运算复合时,必须考虑误差传播。

此外,可以精确表示为以 10 为底的浮点数的有理数,如 0.1 或 0.7,没有精确表示为以 2 为底的浮点数,无论尾数大小如何,它都在内部使用。因此,它们不能被转换成它们内部的二进制对应物,而不会有小的精度损失。这可能会导致令人困惑的结果:例如, floor((0.1+0.7)*10) 通常会返回 7 而不是预期的 8,因为内部表示将类似于 7.9999999999999991118...。

所以永远不要相信浮点数结果到最后一位,也不要直接比较浮点数是否相等。如果需要更高的精度,可以使用任意精度的数学函数和 gmp 函数。

As noted in the warning above, testing floating point values for equality is problematic, due to the way that they are represented internally. However, there are ways to make comparisons of floating point values that work around these limitations.

To test floating point values for equality, an upper bound on the relative error due to rounding is used. This value is known as the machine epsilon, or unit roundoff, and is the smallest acceptable difference in calculations.

Many thanks to all who took the time to answer my question

于 2012-09-28T09:24:29.330 回答