【问题标题】:Round numbers to n number of decimals [closed]将数字四舍五入到小数位数 [关闭]
【发布时间】:2023-12-31 13:49:01
【问题描述】:

问题:

我需要的是 PHP 中的一种方法或函数,可以将具有可变小数位数的数字四舍五入为与成本计算相关的值。

知道产品成本为 0.00023123414123 美元/克是没有意义的,而 0.00023 美元/克会导致非常相似、更实际的成本。当处理少量的东西时,过于准确是低效的。我买不起 0.000231234141 美元,除非我买的东西超过 1000 公斤,否则 0.000231234141 并不比 0.000231 好

上下文:

我正在为一家餐厅开展一个项目,我需要计算产品成本并将结果显示为价格/单位。问题是,根据用户选择的单位,结果可能是 0.25 USD/kg 或 0.00025 USD/g。所以我不能使用 round($var, 2) 因为我不知道需要多少个小数

我将价格和金额存储在数据库的不同列中,并仅为显示结果执行数学运算

让它负责:

假设用户以 36 美元的价格购买了 17 公斤鸡肉,并将费用记录在数据库中。该产品的成本约为 36 美元/17 公斤 = 2.117647058 美元/公斤,我可以四舍五入到 2.11 美元/公斤,到目前为止还不错。但是现在如果用户想知道产品的成本/克,那么相同的数学(在这种情况下是代码)除以产品的货币/数量,我将有 $36/17000g = 0.002117647058 显然不能四舍五入与第一种情况相同的小数位数。

所以我需要一种方法来始终将结果四舍五入为一个干净的数字。

例如:

0.002117647058 => 0.0021

2.117647058 => 2.12

【问题讨论】:

  • 不要舍入和存储,仅在显示时舍入(存储精确值),然后您可以毫无问题地反转,再加上一年多的分数加起来
  • @LawrenceCherone,谢谢我编辑了问题:我将价格和金额存储在数据库的不同列中,并仅为显示结果进行数学运算
  • 浮点数几乎从不干净,无论它们有多少位数。
  • @IgnacioVazquez-Abrams 我知道,我只需要在显示数字之前去掉多余的小数。这个项目是针对小型本地企业的,因此他们不会花费数百万美元,因此一个极其准确的数字在实践中是没有意义的。

标签: php decimal rounding


【解决方案1】:

您可以创建一个查找 0.n 的函数,然后返回迭代值 + $min

<?php
/**
 * Get the decimals value
 * 
 * @param $value
 * @param $min  - min decimals
 * @return int
 */
function get_decimals($value = 0, $min = 2) {
    if ($value === '0.00') {
        return $min;
    }
    for ($i = strlen($value); $i >= $min; $i--) {
        if (strstr($value, '0.'.str_repeat('0', $i), true) !== false) {
            return $i+$min;
        }
    }
    return $min;
}

所以get_float('0.002117647058') 将返回 4,然后可以在 number_format 中使用。

例如:

$values = [
    '0.000000000000000000000000000000000000000000000000000000001', # ¯\_(ツ)_/¯
    '0.002117647058',
    '0.00000000001',
    '2.117647058',
    '999.0',
    '0.1',
    '0.00',
    '0.0',
    '0'
];

foreach ($values as $value) {
    echo number_format($value, get_decimals($value)).PHP_EOL;
}

结果:

0.0000000000000000000000000000000000000000000000000000000010
0.0021
0.000000000010
2.12
999.00
0.10
0.00
0.00
0.00

https://3v4l.org/bmMNe

$min5:

0.0000000000000000000000000000000000000000000000000000000010000
0.00212
0.000000000010000
2.11765
999.00000
0.10000
0.00000
0.00000
0.00000

https://3v4l.org/eD7Gi

【讨论】:

    【解决方案2】:

    如果数字大于 1,您可以使用 round,如果它更小,您可以使用 regex。

    $num = [2.117647058, 0.002117647058];
    
    foreach($num as $n){
        if(substr($n,0,1) > 0){
            echo round($n, 2) . "\n";
        }else{
            preg_match("/([0\.]+)(\d{1,2})/", $n, $m);
            echo $m[0] . "\n";
        }
    }
    

    正则表达式模式匹配 0 和点,然后是下一个或两个后续数字。

    https://3v4l.org/UJ6W1

    【讨论】: