【问题标题】:How to round/ceil/floor a bcmath number in PHP?如何在 PHP 中对 bcmath 数字进行舍入/天花板/地板?
【发布时间】:2010-09-18 20:46:39
【问题描述】:

是否有为此目的的任何库函数,所以我不手动完成并冒着以 TDWTF 结尾的风险?

echo ceil(31497230840470473074370324734723042.6);

// Expected result
31497230840470473074370324734723043

// Prints
<garbage>

【问题讨论】:

标签: php largenumber bcmath


【解决方案1】:

好的,对于我的high-precision Money library,目前在数百个生产站点上,我必须完全重写这个 bcround 功能。我在整个 Internet 上找到的任何内容都与代码无关。

这是我想出的:

/**
 * Based off of https://stackoverflow.com/a/1653826/430062
 * Thanks, [Alix Axel](https://stackoverflow.com/users/89771/alix-axel)!
 *
 * @param $number
 * @param int $precision
 * @return string
 */
function bcround($number, $precision = BCMathCalcStrategy::PRECISION)
{
    if (strpos($number, '.') !== false) {
        if ($number[0] != '-') return bcadd($number, '0.' . str_repeat('0', $precision) . '5', $precision);
        return bcsub($number, '0.' . str_repeat('0', $precision) . '5', $precision);
    }

    // Pad it out to the desired precision.
    return number_format($number, $precision);
}

【讨论】:

    【解决方案2】:

    更新:在这里查看我的改进答案:How to ceil, floor and round bcmath numbers?


    这些功能似乎更有意义,至少对我而言:

    function bcceil($number)
    {
        if ($number[0] != '-')
        {
            return bcadd($number, 1, 0);
        }
    
        return bcsub($number, 0, 0);
    }
    
    function bcfloor($number)
    {
        if ($number[0] != '-')
        {
            return bcadd($number, 0, 0);
        }
    
        return bcsub($number, 1, 0);
    }
    
    function bcround($number, $precision = 0)
    {
        if ($number[0] != '-')
        {
            return bcadd($number, '0.' . str_repeat('0', $precision) . '5', $precision);
        }
    
        return bcsub($number, '0.' . str_repeat('0', $precision) . '5', $precision);
    }
    

    它们支持负数和 bcround() 函数的精度参数。

    一些测试:

    assert(bcceil('4.3') == ceil('4.3')); // true
    assert(bcceil('9.999') == ceil('9.999')); // true
    assert(bcceil('-3.14') == ceil('-3.14')); // true
    
    assert(bcfloor('4.3') == floor('4.3')); // true
    assert(bcfloor('9.999') == floor('9.999')); // true
    assert(bcfloor('-3.14') == floor('-3.14')); // true
    
    assert(bcround('3.4', 0) == number_format('3.4', 0)); // true
    assert(bcround('3.5', 0) == number_format('3.5', 0)); // true
    assert(bcround('3.6', 0) == number_format('3.6', 0)); // true
    assert(bcround('1.95583', 2) == number_format('1.95583', 2)); // true
    assert(bcround('5.045', 2) == number_format('5.045', 2)); // true
    assert(bcround('5.055', 2) == number_format('5.055', 2)); // true
    assert(bcround('9.999', 2) == number_format('9.999', 2)); // true
    

    【讨论】:

    【解决方案3】:

    这对你有用:

    $x = '31497230840470473074370324734723042.9';
    
    bcscale(100);
    var_dump(bcFloor($x));
    var_dump(bcCeil($x));
    var_dump(bcRound($x));
    
    function bcFloor($x)
    {
        $result = bcmul($x, '1', 0);
        if ((bccomp($result, '0', 0) == -1) && bccomp($x, $result, 1))
            $result = bcsub($result, 1, 0);
    
        return $result;
    }
    
    function bcCeil($x)
    {
        $floor = bcFloor($x);
        return bcadd($floor, ceil(bcsub($x, $floor)), 0);
    }
    
    function bcRound($x)
    {
        $floor = bcFloor($x);
        return bcadd($floor, round(bcsub($x, $floor)), 0);
    }
    

    基本上它通过乘以一来找到flooy,精度为零。

    然后它可以通过从总数中减去它来进行 ceil / round,调用内置函数,然后将结果添加回来

    编辑:固定为 -ve 数字

    【讨论】:

    • +1,但可能值得为 bcCeil 和 bcRound 添​​加一个比例参数,因为行为取决于比例。如果你打电话给bcscale(0) 然后试试 bcCeil('1.1') 你会得到 '1' 而不是 '2' 如你所料。允许指定比例将与其他 BCMath 函数一致。
    • 另外需要注意的是,scale参数应该默认为null,如果没有提供,不应该覆盖bcscale设置的值。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-07-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-10
    相关资源
    最近更新 更多