如何正确地对金额进行四舍五入?

3

我在php中使用round()函数遇到了一些小问题,不确定我是否做得正确。(这是一个订单系统)

$amount可以是小数14,8, $price可以是数据库中的小数10,5。

目前我正在使用以下方法进行舍入: $price是一个$amount的价格。

function round_amount($amount) {
  return (float) round($amount, 8);
}

function round_price($amount) {
  return (float) round($amount, 5);
}

//if some one have more decimal chars like 10.000000009
round_amount(10.000000009); //will be 10.00000001

//if some one have more decimal chars like 10.000009
round_price(10.000009); //will be 10.00001

//also this is possible
round_price(round_amount(10.000000009)*round_price(10.000009))

这种使用round舍入的方式正确吗? 有些用户使用了超过16位小数。 我正在对用户数据库中的结果进行加/减。

但是我发现,一些用户多了大约5-10美分!

解决这个问题的唯一方法是只允许使用8和5位小数吗? 并警告用户,如果他试图使用更多? 但是在这种情况下,我会遇到一个问题,即round_cur(round_amount(10.000000009)*round_cur(10.000009))

我希望有人能理解我的意思,或者告诉我我的舍入方式是否正确。

$amount = 10.12398413498579889173459873;
$price = 5.1938457198347695;

echo round_cur(round_amount($amount)*round_cur($price))."<br />";
echo round_cur($amount*$price);

//returns
//52.58245
//52.58241

有趣!


2
round_cur(round_amount(10.000000009)*round_cur(10.000009))的意思是什么?你是不是想要使用round_price? - MIIB
这真的取决于您的用例。不过您的示例似乎有点奇怪,因为您提到了一个round_cur函数,但并没有显示定义,并且您的round_amount(10.0000009)示例应返回10.0000009,因为传递给函数的值比round_amount函数指定的精度要低。现在,将数字相乘然后对其进行舍入,还是先进行舍入再进行相乘,严格来说是业务逻辑决策。 - Mike Brant
1
我会将 round_price(round_amount(10.000000009)*round_price(10.000009)) 改为 round_price((10.000000009*10.000009))。这样你就可以在计算时使用最正确的金额,并在计算完成后对该数字进行四舍五入,而不是之前(更精确)。 - Green Black
@John 我已经更新了。 - DjangoSi
2个回答

1
为什么不将数据库中的实际值缓存,然后再有一个用于显示的变量。这样所有计算都可以在缓存的正确值上完成,同时保持干净的用户界面。只需确保每次更新缓存变量时更新显示的变量即可。
此外,在进行任何舍入之前始终应用数学运算。乘以两个精确数字比乘以两个舍入数字更准确。这适用于数学中的每个操作。因此,先加、减、除、乘,然后再四舍五入,但永远不要使用该舍入数字进行另一个公式。使用先前的精确数字。

在浮点数的世界里,不存在普遍意义上的“两个精确数字”。此外,您没有抓住重点。 - Rok Kralj

-8

我认为你的方法是正确的,但要根据你所提到的情况来看,这两个公式返回不同的值,而你作为项目经理应该考虑哪个系统更适合你(你应该考虑什么对你和用户最好,并做出决定,看看如果你选择其中一个,会有什么交易),对于这种情况,我建议使用第一种方法。

round_price(round_amount(x)*round_price(y))

对于你的问题,一个好的提示或警告应该足够了。给用户举个例子。


10
这是绝对违法的。你不能四舍五入财务数据。 - KatDevsGames

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接