令人惊讶的PHP中的float-int转换

时间:2011-04-13 14:37:33

标签: php floating-point type-conversion

花了一个小时试图找出为什么PHP脚本给了我不正确的输出,结果发现一个循环在一个特定情况下运行了一次迭代。
要解释发生了什么:从XML属性读取版本号(2位,例如1.5或2.0)并乘以100.脚本稍后迭代定义的版本号倍数范围。

事实证明410 == 409,如果你将一个以10为增量的计数器与该值进行比较,就会给出一个有趣的惊喜。

这让我想到了一个问题:我是否从根本上理解了错误?当然,4.1100410应该可以很好地表示为float,并且应该可以很好地转换为int而不会出现舍入错误?

但是,在我的系统上(使用PHP 5.3.2 CLI,Zend Engine 2.3.0),以下测试用例

<?
$a = 100 * 4.1;
$b = (string) $a;
$c = (int) $a;
$d = (int)(string) $a;

var_dump($a);
var_dump($b);
var_dump($c);
var_dump($d);
?>

输出:

float(410)
string(3) "410"
int(409)
int(410)

我现在正在进行(int)(string)转换,但是这是一种令人讨厌的黑客,并不是很漂亮而且感觉不太正确。
是否有更好的(正确的,无破解的)解决方案来获得精确的结果?

6 个答案:

答案 0 :(得分:3)

你的问题出在第一行:

$a = 100 * 4.1;

浮点文字4.1 does not, in fact, have the value 4.1,因此将其乘以100的结果不是410而是少一点。显然,转换为字符串向上舍入,但转换为int向下舍入。

要获得您期望的十进制数学运算,请使用BC Math函数。

答案 1 :(得分:3)

您可以使用BC数学函数获得浮点乘法的可预测结果

http://php.net/manual/en/ref.bc.php

intval(4.1 * 100) === 409
bcmul(4.1, 100) === '410'

答案 2 :(得分:2)

如果一个值只是通过查看它可以很好地转换为浮点数,你通常看不到。请阅读The warning in the manual以获取示例。

答案 3 :(得分:2)

尝试使用intval

$c = intval($a);

编辑:

尝试使用正常舍入对其进行舍入:

$c = round($a, 0, PHP_ROUND_HALF_UP);

答案 4 :(得分:1)

如您所见,乘以4.1将返回一个浮点数。将float转换为int将执行类似floor()的操作,这意味着,如果结果为409.999 ...它将返回409.如果要使用整数,则应该在计算中不要混合浮点值和整数值,或者你应该使用round()来获得最接近的整数。

精确表示的可能值为0.5,0.25,0.125,除以2得到的值,因为该值存储在二进制系统中。

答案 5 :(得分:0)

我用它来解决问题:

round($a);