如何在PHP中舍入/ceil/floor一个bcmath数字


How to round/ceil/floor a bcmath number in PHP?

有没有用于此目的的库函数,所以我不手动执行,并冒着以TDWTF结束的风险?

echo ceil(31497230840470473074370324734723042.6);
// Expected result
31497230840470473074370324734723043
// Prints
<garbage>

更新:在这里查看我改进的答案:如何对bcmath数字进行ceil、floor和round运算


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

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

这将适用于您:

$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);
}

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

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

编辑:固定为-ve数字

好吧,对于我的高精度Money库,它目前在数百个生产站点上,我不得不完全重写这个bcround功能。我在整个互联网上找不到任何符合规范的东西。

以下是我的想法:

/**
 * 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);
}