使用算术运算的类型转换



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

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

由于((0.1 + 0.7) * 10)内部计算为7.999999,当转换为int时,结果为7

我也发现它是对的。看到 Codepad

但是当我试着用更多的例子时,我发现了一些奇怪的东西,比如-

echo (int) ((0.2 + 0.7) * 10); // output 9 (Codepad) echo (int) ((0.7 + 0.7) * 10); // output 14 (Codepad)

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

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

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

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

。我不能精确地表示出来。它的指数为-4,有效位数为7205759403792794/252。也就是说,最接近于1的double是7205759403792794•2-52•2-4 = 0.1000000000000000055511151231257827021181583404541015625。

最接近。7的double的显著性为6305039478318694/252,指数为-1;是6305039478318694•2-52•2-1 = 0.699999999999999999555910790149937383830547332763671875。

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

double最接近的。8是0.8000000000000000444089209850062616169452667236328125。将其与0.1000000000000000055511151231257827021181583404541015625相加,结果为0.9000000000000000499600361081320443190634250640869140625。如你所见,它大于。9。四舍五入并乘以10的最终结果将是9或更大,因此转换为整数的结果为9。

您尝试的其他几个值没有舍入的事实仅仅是偶然发生的。每一个不能精确表示的值都落在两个可表示值之间,一个高一个低。有些更接近较高的值,有些更接近较低的值,你只是碰巧选择了更接近较高的可表示值的值,然后向上四舍五入。

中看到PHP文档:

永远不要将未知分数强制转换为整数,因为这有时会导致意想不到的结果

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

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

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

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

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

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

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

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

要详细了解为什么会出现这种情况,请研究一下浮点表示。但这是一门数学技术学科。

编辑

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

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

定点表示(例如,说前16位是整数值(.之前的部分),后16位是分数值)明显限制了可以表示的数字范围,因为它将最大数字减少到16位整型,并且潜在地浪费了"。"之后可能不需要的所有比特。

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

这就是为什么任何处理货币的计算机系统都不会将值存储为浮点数(例如,1.10英镑总是存储为110p)。任何对精度要求很高的系统都应该执行和整型一样多的算术运算,并在最后一步除成浮点数。

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

alert((0.1+0.7)*10); // alerts 7.9999999999

intval代替,更可靠。

最新更新