php 使用小数 (10,3) 的计算有时会导致指数
php calculation with decimal(10,3) results in exponential sometimes
在我的 php 脚本中,我对 MySQL 数据库中的条目进行了计算。数据库中的相关字段定义为 decimal(10,3)
。这是一个会计平台,我必须在每个条目中检查借方 = 贷方。
我通过以下操作来做到这一点:
$sumupNet = 0;
$sumup = 0;
foreach($val['Record'] as $subkey => $subval)
{
$sumupNet = $sumupNet + $subval['lc_amount_net'];
$sumup = $sumup + $subval['lc_amount_debit'] - $subval['lc_amount_credit'];
}
现在我们说每个条目都是正确的,然后 $sumupNet 和 $sumup 结果为 0
。在大多数情况下,这是有效的。但在某些情况下,结果是这样的:-1.4432899320127E-15
或这个 -8.8817841970013E-15
。如果我手动计算这个值,结果是 0
。我猜想(不确定)上面的结果是接近0的数字,以指数形式输出。
所以我想我必须转换一些东西或者我的计算是错误的。但是什么?我在某些时候尝试了 floatval() 但没有用。如果有人有提示,我非常感谢你。
你得到这个是因为你在用浮点值做数学运算。 Read some theory about it.
你真的不想那样计算钱,因为你可能会遇到你无法真正解决的奇怪的舍入问题。
对于PHP,有很多库可以帮你规避问题,比如BC Math, or GMP.
其他解决方案是使用货币具有的最小货币值(如美分)计算所有值,因此您始终使用整数。
这些是四舍五入的问题。当我们谈论浮动时,这些是完全正常的。举个日常的例子,
1/3 = 0.3333333333333333...333333333...3333...
原因:10与3互质。你可能想知道10是从哪里来的。我们对数字使用 10 基,也就是说,每当我们谈论一个数字时,它的数字代表 10 基指数值。计算机使用二进制数,即 2 基数。这意味着用这样的数字除法通常会产生无穷无尽的数字序列。例如,1/3 作为二进制数如下所示:
0.010101010101010101010101010101010101010101010101010101...
小数类型表示十进制数,即十进制数。之后的部分使用三位数字。让我们假设您的电话号码是这样结尾的:
.xyz
这意味着:
xyz / 1000
但是,1000可以被下列质数整除:
2 和 5。
由于 5 与 2 互质,因此当您将除以 5 的结果表示为二进制数时,结果可能会是无限循环的数字。 1/5 作为二进制数如下所示:
0.0011001100110011001100110011001100110011001100110011...
由于计算机无法存储无穷无尽的数字,所以它必须对数字进行四舍五入,即找到一个接近于它的值并且可以更容易地表示的数字。如果将数字 a 舍入为 b 并且两个数字不相等,则会丢失一定量的精度,这就是您提到的错误的原因。
你可以这样解决问题:当你select数据库中的值时,将它们乘以1000(从而将它们转换为整数),然后检查操作。最后,除以 1000。
在我的 php 脚本中,我对 MySQL 数据库中的条目进行了计算。数据库中的相关字段定义为 decimal(10,3)
。这是一个会计平台,我必须在每个条目中检查借方 = 贷方。
我通过以下操作来做到这一点:
$sumupNet = 0;
$sumup = 0;
foreach($val['Record'] as $subkey => $subval)
{
$sumupNet = $sumupNet + $subval['lc_amount_net'];
$sumup = $sumup + $subval['lc_amount_debit'] - $subval['lc_amount_credit'];
}
现在我们说每个条目都是正确的,然后 $sumupNet 和 $sumup 结果为 0
。在大多数情况下,这是有效的。但在某些情况下,结果是这样的:-1.4432899320127E-15
或这个 -8.8817841970013E-15
。如果我手动计算这个值,结果是 0
。我猜想(不确定)上面的结果是接近0的数字,以指数形式输出。
所以我想我必须转换一些东西或者我的计算是错误的。但是什么?我在某些时候尝试了 floatval() 但没有用。如果有人有提示,我非常感谢你。
你得到这个是因为你在用浮点值做数学运算。 Read some theory about it.
你真的不想那样计算钱,因为你可能会遇到你无法真正解决的奇怪的舍入问题。
对于PHP,有很多库可以帮你规避问题,比如BC Math, or GMP.
其他解决方案是使用货币具有的最小货币值(如美分)计算所有值,因此您始终使用整数。
这些是四舍五入的问题。当我们谈论浮动时,这些是完全正常的。举个日常的例子,
1/3 = 0.3333333333333333...333333333...3333...
原因:10与3互质。你可能想知道10是从哪里来的。我们对数字使用 10 基,也就是说,每当我们谈论一个数字时,它的数字代表 10 基指数值。计算机使用二进制数,即 2 基数。这意味着用这样的数字除法通常会产生无穷无尽的数字序列。例如,1/3 作为二进制数如下所示:
0.010101010101010101010101010101010101010101010101010101...
小数类型表示十进制数,即十进制数。之后的部分使用三位数字。让我们假设您的电话号码是这样结尾的:
.xyz
这意味着:
xyz / 1000
但是,1000可以被下列质数整除:
2 和 5。
由于 5 与 2 互质,因此当您将除以 5 的结果表示为二进制数时,结果可能会是无限循环的数字。 1/5 作为二进制数如下所示:
0.0011001100110011001100110011001100110011001100110011...
由于计算机无法存储无穷无尽的数字,所以它必须对数字进行四舍五入,即找到一个接近于它的值并且可以更容易地表示的数字。如果将数字 a 舍入为 b 并且两个数字不相等,则会丢失一定量的精度,这就是您提到的错误的原因。
你可以这样解决问题:当你select数据库中的值时,将它们乘以1000(从而将它们转换为整数),然后检查操作。最后,除以 1000。