【问题标题】:bcadd really necessary when calculating shopping cart total?bcadd 在计算购物车总数时真的有必要吗?
【发布时间】:2011-04-19 22:29:29
【问题描述】:

考虑到浮点数不精确并且我应该使用 BCMath 函数来获得精确结果的事实,是否真的有必要在 PHP 中使用价格字符串并在制作“简单”购物车时将它们与 bcadd 相加?

鉴于以下示例,我为什么不应该使用圆角浮点数?

我正在寻找计算购物车订单总额的最佳做法。

    $floatTotal = 0.00;
$stringTotal = '0.00';

for($i=0; $i<1000; $i++) {
    $floatTotal += 0.1; 
}
echo "float value: ";
printf('%.40f', $floatTotal); //99.9999999999985931253831950016319751739502

echo "<br>\n";

echo "rounded float value: ". round($floatTotal); //100

echo "<br>\n";

for($i=0; $i<1000; $i++) {
    $stringTotal = bcadd($stringTotal, '0.1', 2);
}

echo 'string value: '.$stringTotal.'<br>'; //100.00

【问题讨论】:

  • 将您的货币金额存储为便士。然后转换为常规美元值是除以 100 的简单问题,并且还消除了任何浮点错误。
  • 但是相对简单的购物车有多大必要呢?您是否遇到过舍入错误?
  • 如果您正在处理货币价值,那么不要使用浮点数,句点。无论多么复杂或多么简单。要么将货币值作为便士存储在 INT 字段中,要么使用数据库的“十进制”类型,即 FIXED 点存储。这不是问题或浮点错误有多频繁/罕见。它存在,除非你想成为 IEEE 754 方面的专家,否则不要使用它们
  • @Marc B:他的问题并没有专门针对持久性存储。 185 美分的 25% 产生 46.25 的折扣。浮点数会抬起他们丑陋的脑袋,不管是不是小单位。
  • 无论如何你都必须四舍五入,但存储为 penny-ints 可以消除至少一个浮点引起的错误来源。对于“小”错误,差异可能只出现一分钱,但在某个地方有人在看超人三世并邪恶地咯咯笑。

标签: php


【解决方案1】:

您应该切勿对货币使用浮点值。它们并不准确。相反,以最小单位(美分、便士等)存储货币值,以便您可以使用整数。在这种情况下,没有理由使用 bcmath 库,除非您正在处理不太可能的巨大值。

【讨论】:

  • 我将货币作为 DECIMAL 存储在 MySQL 数据库中,我知道理论,但对于简单的购物车来说有多大必要?
  • 不能再同意了。使用浮点数作为货币只是麻烦。坚持美分,你会很高兴你做到了。
  • @Youri 无论应用程序如何,将钱存储为美分更加精确。即使在一个小购物车中,一旦你必须申请税收、优惠券、折扣等,你就不得不向上或向下舍入,这是不好的。使用美分不再复杂,优势巨大。
  • 因此使用美分比将值存储为 DECIMAL 在数据库中并在 php 中使用 BCMath 更好?
【解决方案2】:

尽管前一段时间有人问过这个问题,而且除了使用最小分母存储值之外。

从长远来看,PHP 有一种方法可以在不使用 BCMath 的情况下搞砸事情,但这取决于您在 PHP 中设置的精度,而不考虑浮点值的大小。 IIRC MySQL 会将您的十进制值作为字符串输出到 PHP 而不是浮点数。在 PHP 中对字符串值执行任何数学运算都会将它们转换为浮点数。 BC 数学函数也不会round 值,它们会被截断到定义的精度。

也就是说,由于您在 MySQL 中将值存储为十进制,因此您可以从数据库中执行数学运算,而不是使用非常昂贵的 PHP bcmath 函数。

参考:https://dev.mysql.com/doc/refman/5.0/en/precision-math.html

甚至可能创建视图、触发器或存储过程来处理值,以节省您的时间并保持一致性或使用 ORM。

SELECT ((quantity * price) * tax) AS total FROM Table1;  

http://sqlfiddle.com/#!9/05435/1

*注意我将十进制和浮点列的大小和比例设置为32,16 以显示二进制精度。我还使用了常见的0.2*0.3 示例。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-31
    相关资源
    最近更新 更多