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

后端 未结 3 1128
野性不改
野性不改 2020-12-19 01:46

Is there any library function for this purpose, so I don\'t do it by hand and risk ending in TDWTF?

echo ceil(31497230840470473074370324734723042.6);

// Exp         


        
相关标签:
3条回答
  • 2020-12-19 02:08

    This will work for you:

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

    Basically it finds the flooy by multiplying by one with zero precision.

    Then it can do ceil / round by subtracting that from the total, calling the built in functions, then adding the result back on

    Edit: fixed for -ve numbers

    0 讨论(0)
  • 2020-12-19 02:30

    OK, for my high-precision Money library, which is currently on hundreds of production sites, I had to completely rewrite this bcround functionality. Nothing I found on the entire Internet was up to code.

    Here's what I came up with:

    /**
     * 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);
    }
    
    0 讨论(0)
  • 2020-12-19 02:32

    UPDATE: See my improved answer here: How to ceil, floor and round bcmath numbers?.


    These functions seem to make more sense, at least to me:

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

    They support negative numbers and the precision argument for the bcround() function.

    Some tests:

    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
    
    0 讨论(0)
提交回复
热议问题