【问题标题】:PHP: Ceil function rounding issue [duplicate]PHP:Ceil 函数舍入问题 [重复]
【发布时间】:2019-01-07 09:19:49
【问题描述】:

在我的一个 wordpress 主题功能中,此代码用于计算总计费金额:ceil(($cost * (1 + ($charges / 100))) * 100);

以下情况发生了一点误判。

场景:

$charges = 9;
$cost = 100;

echo ceil(($cost * (1 + ($charges / 100))) * 100);

上面的代码输出10901,而它应该是10900

工作正常适用于其他场景,例如:

$charges = 4;
$cost = 90.7;

echo ceil(($cost * (1 + ($charges / 100))) * 100); 
//outputs 9433, which is fine because manual calculation results 9432.8

问题:

  1. 为什么会这样?
  2. 如何防止这种情况发生?
  3. 有任何替代函数可以舍入到下一个最接近的整数吗? (仅当金额为浮点值时)

【问题讨论】:

  • @Phil 这些答案都没有帮助,首先,这不是数学问题。其次,它几乎可以正常工作,但仅对以 00 结尾的特定数字导致错误。请取消标记问题或分享有用的资源。谢谢
  • 看来您确实正在面临由数值准确性引起的问题。虽然我发现简化您的方程式确实有帮助:ceil($cost*(100+$charge));,请参阅此处:rextester.com/QQEYOS31143
  • 感谢@cars10m,还有另一个问题。您的方程式在 rextester.com 上运行良好,但在我的服务器上,它有同样的问题。 :( 我正在运行 5.6.32
  • @Alena 它肯定是一个浮点算术问题。例如,100 * (1 + (9 / 100)) 显示为 109.00000000000001。这就是为什么ceil() 似乎正在四舍五入。请阅读我在您的问题顶部链接的两个帖子
  • 在使用 ceil() 函数之前,您可以尝试使用 round($cost*(100+$charge),6) 舍入到小数点后 6 位最接近的数字。但是,据报道round() 在某些情况下是错误的。否则,您也可以通过创建一个圆角字符串来绕道,例如sprintf('%0.6f',$cost*(100+$charge)),然后继续对其进行数学运算(它将隐式转换回浮点数)。在这两种情况下,ceil() 函数将在之后应用以将值转换为“下一个更大的整数”。

标签: php rounding


【解决方案1】:

问题是您将 ceil 应用于外部表达式。尝试改写为:

$charges = 9;
$cost = 100;

echo ($cost + ceil($cost * $charges / 100)) * 100;

这会按预期输出10900

更新

正如@cars10m 建议的那样,简化表达式确实有帮助:

echo ceil($cost * 100  + $cost * $charges);

更新 2

您还可以使用BCMath 库进行精确数学运算:

bcscale(6);
echo ceil(bcadd(bcmul($cost, 100), bcmul($cost, $charges)));

【讨论】:

  • 感谢@Olim Saidov,但这不适用于其他场景。用这些值试试$charges = 4; $cost = 90.7; 它的结果是9470 而它应该是9433
  • 能解释一下计算逻辑吗?为什么应该是9433
  • 1) 费用/100 = 0.04 2) 0.04 + 1 = 1.04 3) 1.04 * 成本 = 94.328 4) 94.328 * 100 = 9432.8 5) 舍入到下一个整数将使其成为9433跨度>
  • 新解决方案在我的服务器上不起作用。我正在运行5.6.32
  • 使用@cars10m 方法,rextester 给出了正确的结果,但在我的服务器上,它给出的结果与我的旧表达式相同。也许那是因为 php 版本等。但是,bcscale 似乎工作。我将执行不同的测试并很快回来。谢谢您的帮助! :)
猜你喜欢
  • 2018-07-28
  • 2011-11-22
  • 1970-01-01
  • 1970-01-01
  • 2020-09-17
  • 2016-02-29
  • 2012-07-31
  • 1970-01-01
  • 2016-11-03
相关资源
最近更新 更多