繁体   English   中英

MySQL和PHP的十进制精度错误

[英]MySQL & PHP decimal precision wrong

24151.40-31891.10 = -7739.699999999997

我从类型为十进制(14,2)24151.40 31891.10的MySQL表中获取了这两个数字。它的存储方式与上面所述完全相同,并且与PHP完全相同。 但是当我从第一个值减去第二个值的那一刻,我得到一个数字-7739.699999999997而不是-7,739.7。 为什么要特别精确? 它是从哪里来的?

我为Authorize.Net撰写的文章中

一加一等于二,对吧? .2加1.4乘10怎么样? 等于16,对吧? 如果您正在使用PHP(或大多数其他编程语言)进行数学运算,则不会:

echo floor((0.2 + 1.4) * 10); // Should be 16. But it's 15!

这是由于内部如何处理浮点数。 它们用固定的小数位数表示,并且可能导致数字的总和与您期望的不完全相同。 在内部,我们的.2加1.4乘10示例计算得出大约为15.9999999998左右。 当使用不必像百分比这样精确的数字时,这种数学很好。 但是,在使用货币精度时,问题很重要,因为这里或那里丢失的一分钱或一美元很快就累加了,没有人会喜欢在任何丢失的钱的短端上。

BC数学解决方案

幸运的是,PHP提供了BC Math扩展 ,它是“针对任意精度数学,PHP提供了支持任何大小和精度的数字(以字符串表示)的二进制计算器”。 换句话说,您可以使用此扩展程序对货币值进行精确的数学运算。 BC Math扩展包含使您能够精确执行最常见操作的函数 ,包括

一个更好的例子

这是与上述相同的示例,但是使用bcadd()函数为我们做数学运算。 它包含三个参数。 前两个是我们希望添加的值,第三个是我们希望精确到的小数位数。 由于我们要花钱,所以我们将精度设置为两位小数。

echo floor(bcadd('0.2', '1.4', 2) * 10); // It's 16 like we would expect it to be.

PHP没有MySQL那样的小数类型,它使用浮点数; 浮法因不准确而臭名昭著。

要解决这个问题,请查看number_format ,例如:

echo number_format(24151.40 - 31891.10, 2, '.', '');

为了更精确地进行数字运算,您还可以查看PHP的数学扩展:

http://www.php.net/manual/zh/refs.math.php

这与一般的浮点/双精度比率有关,科学上与1.FRACTAL * 2 ^指数幂相关。 由于前缀为1,因此从技术上讲没有零,并且您可以获得的最接近值为0的值是1.0 * 2 ^ -127,即.000000 [127 0s] 00001

通过将您的答案四舍五入到一定的精度,舍入因子将为您提供更精确的答案

http://dev.mysql.com/doc/refman/5.0/en/mathematical-functions.html#function_round

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM