简单乘法的PHP舍入错误

简单乘法的PHP舍入错误,php,casting,int,rounding,Php,Casting,Int,Rounding,当使用(int)强制转换变量时,PHP似乎舍入错误。为什么? $multiplier = 100000000; $value = 0.01020637; echo (int)($value*$multiplier); 输出:1020636。(意外输出) 输出:1020637。(预期正确输出) 编辑:情况变得更糟 $multiplier = 100000000; $value = 0.01020637; echo $temp = ($value*$multiplier); echo '<b

当使用
(int)
强制转换变量时,PHP似乎舍入错误。为什么?

$multiplier = 100000000;
$value = 0.01020637;
echo (int)($value*$multiplier);
输出:
1020636
。(意外输出

输出:
1020637
。(预期正确输出)

编辑:情况变得更糟

$multiplier = 100000000;
$value = 0.01020637;
echo $temp = ($value*$multiplier);
echo '<br/>';
echo (int)$temp;
$multiplier=100000000;
$value=0.01020637;
echo$temp=($value*$multiplier);
回声“
”; 回声(内部)$温度;
输出:

1020637


1020636

在处理浮点运算时,事情可能会变得棘手,浮点数学(以及涉及的问题)很容易理解,但在您不期望它们出现时,事情可能会突然出现。就像这里发生的那样。在处理浮点运算时,您可以广泛阅读或使用语言提供的工具

当您关心所涉及的精度时,您应该使用该函数。它是一个“可选”扩展,但如果您关心精度,那么它很快就会被要求

例如:

multiplier = 100000000;
$value = 0.01020637;
echo (int)($value*$multiplier);
echo "\n";
echo bcmul($value, $multiplier, 0);

示例:

要在PHP中对浮点进行取整,应使用round()函数。仅强制转换为整数不会正确舍入值

第一个参数是要四舍五入的浮点数(本例中的计算结果),第二个参数是可选的,并指定要返回的小数量(也称为精度)。还有第三个参数,控制模式。它们可以是PHP_ROUND_HALF_UP、PHP_ROUND_HALF_DOWN、PHP_ROUND_HALF_偶数或PHP_ROUND_HALF_奇数

示例来自:


下面是代码()的示例:


PHP(特别是在32位版本中)存在浮点数问题。这就是为什么将
float
强制转换为
int
会产生不可预测的结果。有关更多详细信息,请参见第页。基本上,你在数学上得到了微小的不精确性,当你尝试做类似于
ceil()的事情时,这可能会导致严重的问题

如果您真的需要将数字转换为
int
,我建议您先将数字四舍五入

$multiplier = 100000000;
$value = 0.01020637;
$temp = round($value*$multiplier);
echo $temp . '<br/>' . (int)$temp;
$multiplier=100000000;
$value=0.01020637;
$temp=四舍五入($value*$multiplier);
echo$temp.”
。(内部)$temp;

这是通过截断小的浮点错误来实现的。虽然也可以进行截断,但它不是PHP核心的一部分,也不是一个好的整体解决方案。最好的办法是自己编写一个舍入例程,以返回所需的精度。在我工作的项目中,我们就是这么做的。我们编写了自己的舍入函数,它解决了您将遇到的问题。如果不知道你想做什么,很难说这是否是你所需要的,但这是我们在没有bcmath的情况下所做的。

你看到的问题如下: 将这样的两个数字相乘时:

$mulitply = 0.1 * 100;
你不是用0.1乘以100,而是用0.09999998。。。 当涉及到
(int)
时,它会将像
4.999
这样的数字转换为
4
,因此当使用
(int)
计数时,您的结果
1020636.99999999
将变成
1020636

$test =  (int) bcmul('100000000', '0.01020637');
echo $test

返回正确答案

如果您尝试(int)($value*$multiplier+0.5)会怎么样;“
切勿将未知分数强制转换为整数,因为这有时会导致意外结果。
”摘自PHP integer手册。这可能是原因吗?什么是“未知分数”?在我的程序中,
($value*multiplier)
表达式将始终解析为整数。将其切换为read
($value*$multiplier)(int)
会有帮助吗?或者干脆
$temp=($value*$multiplier)$intVal=(int)$temp)
可能会导致预期的结果吗?@bvpx老实说,我不知道。但是我确实发现这个链接,描述了一个与您类似的问题,请查看:应该注意的是,bcmath不是PHP核心函数的一部分,也不是所有服务器都安装了它。没有bcmath,有什么方法可以做到这一点吗?目前我的服务器没有安装它。也许我可以找到一个只包含bcmul函数的库,并将其包含在我的项目中?我怀疑您是否能在这里找到一个很棒的userland解决方案。我可能会礼貌地缠着你的系统管理员安装扩展。在精度至关重要的情况下,我该如何解决这个问题?@bvpx我建议
BC数学函数
(,在你的情况下,你需要专门查找
bcmul()
函数)或
gmp\u mul()
()@bvpx我注意到您询问了一个不需要在PHP中安装其他内容的解决方案。我从一开始就不知道PHP中包含任何类似的函数,我很震惊。@bvpx同样,如果不需要在服务器端执行此计算,我强烈建议使用纯JavaScript。简单地使用:
var multiply=var_1*var_2
不会自动给出一个四舍五入的答案,它会给你一个完整的10位小数。该应用程序是一个小型PHP程序,分发到许多计算机上,只运行服务器端,因此我需要将其设置为“裸体”尽可能确保它运行的服务器没有安装bcmath的问题,但也能够正确存储这些值。我有一种直觉,即使用
round()
将导致比它解决的问题更多的问题…我希望我可以告诉您不同的情况,但除了将其舍入,没有其他方法可以获得一个干净的数字。bcmath是一个硬截断,以确保您不会遇到那些奇怪的精度问题。你知道你需要多少精度吗?我有点不确定如何回答“我需要多少精度”,但我正在使用的数字将在10000000到0.00000001之间,所有这些数字都需要乘以100000000并正确存储到数据库中。如果必须在服务器上安装bcmath,我不想使用它,但数据库中不能存储不正确的值,这一点非常重要。基本问题是您的号码存储在内存中,类似于
1020636.9999992734834
$multiplier = 100000000;
$value = 0.01020637;
$temp = round($value*$multiplier);
echo $temp . '<br/>' . (int)$temp;
$mulitply = 0.1 * 100;
$test =  (int) bcmul('100000000', '0.01020637');
echo $test