3

今天在阅读参考书时,我遇到了一个例子:

echo (int) ((0.1 + 0.7) * 10); // output 7

因为((0.1 + 0.7) * 10)在内部评估为7.999999,当转换为时int,结果7

我也觉得是对的。请参阅键盘

但是当我尝试更多示例时,我发现了一些奇怪的东西,例如-

echo (int) ((0.2 + 0.7) * 10); // output 9键盘

echo (int) ((0.7 + 0.7) * 10); // output 14键盘

还有很多。每次我更改值时,它都会给我正确的答案。

我想知道为什么只((0.1 + 07) * 10)产生与其他结果不同的结果。

这真的很奇怪还是我错过了什么?

4

5 回答 5

3

在常见的双精度格式中,数字用符号位、11 位指数和称为有效数的 53 位小数部分表示。有效数字始终是一个 53 位非负整数除以 2 52(也可以用二进制写为一个二进制数字、一个小数点和另外 52 个二进制数字)。

.1 无法准确表示。它用 -4 的指数和 7205759403792794 / 2 52的有效数字表示。也就是说,最接近double0.1 的是 7205759403792794•2 -52 •2 -4 = 0.1000000000000000055511151231257827021181583404541015625。

最接近double0.7 的有效数字为 6305039478318694 / 2 52,指数为 -1;它是 6305039478318694•2 -52 •2 -1 = 0.6999999999999999555910790149937383830547332763671875。

当您将这两个数字相加时,结果为 0.7999999999999999611421941381195210851728916168212890625。这在 a 中也不能完全表示double;它必须四舍五入到最接近的可表示值,当你乘以 10 时,它必须再次四舍五入。但是,您可以看到总和小于 0.8。最终结果小于 8,因此转换为整数会将其截断为 7。

最接近的double0.8 是 0.8000000000000000444089209850062616169452667236328125。当您将其添加到 0.1000000000000000055511151231257827021181583404541015625 时,总和为 0.9000000000000000499600361081320443190634250640869140625。如您所见,它大于 0.9。舍入和乘以 10 的最终结果将是 9 或更大,因此转换为整数会产生 9。

您尝试的其他几个值没有四舍五入的事实仅仅是偶然的。每个不能精确表示的值都介于两个可表示值之间,一个高一个低。有些更接近较高的值,有些更接近较低的值,而您恰好选择了更接近较高可表示值并向上四舍五入的值。

于 2013-04-24T14:11:07.917 回答
1

在PHP 文档中看到:

切勿将未知分数转换为整数,因为这有时会导致意外结果

<?php
    echo (int) ( (0.1+0.7) * 10 ); // echoes 7!
?>

所以是的,结果很奇怪,因为意外((0.1+0.7) * 10 的内部表示就像 7.99999...)

PHP 文档中有关浮点精度的更多信息。

于 2013-04-24T09:26:12.267 回答
0

计算机处理绝对;它们不能在位级别明确表示分数。这是使用浮点表示来解决的,这是一种表示实数近似值的方法。

不幸的是,有些数字不可能 100% 准确地表示,这会导致在处理浮点运算时不精确。

有关确切原因的更多信息,请对浮点表示进行一些研究。但这是一门相当数学技术的学科。

编辑

让我澄清一下。我们都知道计算机处理二进制。它们读取、写入和处理 1 或 0 的位。

32 位处理器通常会将内存划分为 4 字节的块。所以整数和浮点数的默认大小是 4 字节,或 32 位。用二进制表示一个整数(一个 int)很容易。数字 8 是:00000000 00000000 00000000 00001000。但是计算机如何表示十进制数?请记住,它只能看到 1 和 0;它不能只放置一个“。” 在他们中间!

定点表示(例如,说前 16 位是整数值(. 之前的部分),后 16 位是小数值)显着限制了可以表示的数字范围,因为它减少了最大数字到 16 位 int 并可能浪费“。”之后的所有位。可能不需要。

因此计算机使用一种称为浮点表示的技术,其中数字使用编码指数进行缩放。所以数字的一部分是指数,一部分是分数。与定点表示法相比,这大大增加了可能数字的范围。但是有些数字无法完全精确地表示。

这就是为什么任何处理货币的计算机系统从不将值存储为浮点数(例如,1.10 英镑将始终存储为 110p)。任何需要精度的系统都应该执行与 int 一样多的算术运算,并在最后一步将任何除法转换为浮点数。

请注意,这不仅仅是一个 PHP 问题,它存在于所有语言中。例如,JavaScript:

alert((0.1+0.7)*10); // alerts 7.9999999999
于 2013-04-24T09:29:15.180 回答
0

这是由于使用浮点数时舍入不精确例如:

0.1 + 0.7 = 0.7999999999
0.7999999999 * 10 = 7.999999999
floor(7.999999999) = 7

解决这个问题的方法是在类型转换之前进行舍入。

于 2013-04-24T09:25:35.010 回答
-1

使用intval它,它更可靠。

于 2013-04-24T09:29:48.173 回答