6

我的 MySQL 数据库中有一个客户发票表,其中包含一个名为 price 的 DECIMAL(10,2) 字段。

在 php 中获取这些值并计算总金额时,

例如:在脚本中

$totalAmount = 0; // initialised them to 

   while(records){              

       $amount = $inv_amount - ($pay_amount + $onamount); //float i guess. 2.22, 14.22
       $totalAmount = $totalAmount + $amount; //float i guess. 2.22, 14.22 ..etc

    }

echo $totalAmount;它在最终数量 0.01 中有一个小错误但是在处理 20,000 左右的大型数据集时,这个错误变得非常可观,例如 200+

在 PHP 中处理价格等这些数字时,最安全的方法是什么?或者我最终会出现潜在的舍入错误以及在处理浮点数据类型时常见的问题?

正在使用

round 
number_format

是最适合此类金融应用的解决方案吗?

4

7 回答 7

11

事实上,浮点数并不精确。
以美分计算(乘以 100 并以整数计算),或使用BC Math以字符串计算。

于 2012-06-20T07:39:13.630 回答
4

试试这个:

$totalAmount = number_format($totalAmount, 2, '.', '');
于 2012-06-20T07:48:50.083 回答
2

如果您需要小数点后 2 位的精度:

  1. 将值乘以 100
  2. 做你的操作
  3. 除以 100 并number_format在适当时使用
于 2012-06-20T07:39:14.940 回答
0

你试过了吗

round(totalAmount, 2, PHP_ROUND_HALF_ODD);

它应该看到最后一个十进制数字 - 如果它是奇数 - 向下舍入,如果是偶数 - 向上

于 2012-06-20T07:39:37.550 回答
0

好吧,首先,当您可以在 mysql 中执行此操作时,为什么要在 php 循环中求和?此外,只需使用整数乘以 100,然后在需要最终结果时除以 100。

于 2012-06-20T07:39:46.347 回答
0

我建议使用查询或视图在 SQL 级别上进行计算。

首先,在 PHP 上使用 64 位整数是有风险的,因为:在溢出时,它会切换到浮动并且您会失去精度。如果是钱,问题就更严重了。您应该用 sql 计算一列并从那里获取值。Money 是一种长期类型,它通常会转换为浮动在 php 上,您的人会根据 php 引擎的心情输掉或赢取一些美分。您不能在 php 上使用小数类型,即使您乘以 100 并将其保留为整数,带有溢出的长数字将自动转换为浮点数。如果您想使用十进制数字或将您的字段转换为 int,请在 MYSQL 上计算您的值。

如果您的服务器有 32 位 cpu,则 WORD 长度为 32 位,因此 php 引擎中的整数是 32 位整数。这使得溢出的可能性更高。在 64 位系统上,您可以更舒适地工作。

在这种情况下,对货币价值使用舍入函数是荒谬和不专业的。不要这样做。

阅读本文档将对您有很大帮助。

整数的php文档说

整数溢出

如果 PHP 遇到超出整数类型范围的数字,它将被解释为浮点数。此外,导致数字超出整数类型范围的操作将改为返回浮点数。

SQL 级别的计算将确保货币类型的准确性。将货币类型设置为 php 将产生一个浮点值,您可以将其乘以 100 然后再除以 100 但它再次增加了溢出的风险,因为 php 将使用 32 位浮点数进行存储。如果您使用 32 位浮点数,为什么数据字段是十进制的?所以如果你这样做是不一致的。一个 32 位数字我已经不是那么大了,一个 32 位浮点数在浮点数上失去了一些容量,所以当你乘以 100 时它更有可能达到容量过剩。

使用 SQL

于 2012-06-20T07:45:15.157 回答
0

你可以使用number_format

例如:(两位小数)

$number = 12345.5667;
echo $result = number_format($number, 2);

或者你可以round在 MySql 中使用函数:

ROUND(number,2)
于 2012-06-20T07:49:01.253 回答