3

I cannot seem to figure out how to always round up in PHP. ceil() would be the obvious choice but I need the same functionality that round() provides with its second parameter "precision". Here is an example:

// Desired result: 6250
echo round(6244.64, -2); // returns 6200
echo round(6244.64, -1); // returns 6240
echo ceil(6244.64) // returns 6245

I need the number to always round up so that I can calculate an equal divisor based on parameters for a chart.

6 Answers 6

5

From a comment on http://php.net/manual/en/function.ceil.php:

Quick and dirty `ceil` type function with precision capability.

function ceiling($value, $precision = 0) {
    return ceil($value * pow(10, $precision)) / pow(10, $precision);
}
Sign up to request clarification or add additional context in comments.

6 Comments

I think the operation order is mixed up, you'd need to divide before ceil, then multiply, not the other way around, no?
@njk: ceiling(6244.64, -1) gives the desired result 6250. Notice that the precision is negative in this case.
This will return true: ceiling(77.4, 2) === 77.41. The function is broken.
@bzeaman... I don't think the function is broken. asking for the ceiling of 77.4 with two decimal precision is like asking for ceiling( 77.400 , 2 )
@user1822391 Yes, 77.4 is the same as 77.400 etc., but the ceiling of 77.4 simply should not yield 77.41.
|
4

Some of these answers have issues with floating point arithmetic which can fail as shown in this answer. For a bulletproof solution in all cases, use these:

/**
 * Used to round up based on the decimal place, for example rounding up to the nearest penny
 * http://stackoverflow.com/questions/8239600/rounding-up-to-the-second-decimal-place
 * @param float $value
 * @param integer $precision
 * @return number
 */
public function Ceiling($value, $precision = 0) {
    $offset = 0.5;
    if ($precision !== 0)
        $offset /= pow(10, $precision);
    $final = round($value + $offset, $precision, PHP_ROUND_HALF_DOWN);
    return ($final == -0 ? 0 : $final);
}

/**
 * Used to round up based on the decimal place, for example rounding up to the nearest penny
 * http://stackoverflow.com/questions/8239600/rounding-up-to-the-second-decimal-place
 * @param float $value
 * @param integer $precision
 * @return number
 */
public function Floor($value, $precision = 0) {
    $offset = -0.5;
    if ($precision !== 0)
        $offset /= pow(10, $precision);
    $final = round($value + $offset, $precision, PHP_ROUND_HALF_UP);
    return ($final == -0 ? 0 : $final);
}

Comments

2

As version ceil(pow(10, $precision) * $value) / pow(10, $precision); fails in some cases, e.g. round_up(2.22, 2) gives incorrect 2.23 as mentioned here, so I have adapted this string solution for round_down() to our round_up() problem. This is the result (a negative precision is not covered):

function round_up($value, $precision) {        
    $value = (float)$value;
    $precision = (int)$precision;
    if ($precision < 0) { 
        $precision = 0;
    }
    $decPointPosition = strpos($value, '.');
    if ($decPointPosition === false) { 
        return $value;
    }
    $floorValue = (float)substr($value, 0, $decPointPosition + $precision + 1);
    $followingDecimals = (int)substr($value, $decPointPosition + $precision + 1);
    if ($followingDecimals) {
        $ceilValue = $floorValue + pow(10, -$precision); // does this give always right result?
    }
    else {
        $ceilValue = $floorValue;
    }
    return $ceilValue;                
}

I don't know it is bulletproof, but at least it removes the above mentioned fail. I have done no binary-to-decimal-math-analysis but if $floorValue + pow(10, 0 - $precision) works always as expected then it should be ok. If you will find some failing case let me know - we should look for another solution :)

1 Comment

Good idea to work with integer part and decimal part, but you should then work with single characters. This function does not work with ceiling(77.401, 2) that produce float(77.41000000000001) instead of float(77.41). Best answer is that of Nico Westerdale
0

You could divide by 10, ceil(); and then multiply by ten

Comments

0
echo 10*ceil($number/10);

Comments

-1

One more solution for ceil with precision, no pow, it looks like works 9 digits both sides:

$v = 123400100100100101;
$a1 = 444444444.4;
$a2 = .04444444444;
$b1 = 111111111.1;
$b2 = .01111111111;
echo $v . "\n";
for ($i = 0; $i < 18; $i ++) {
    $v = $v/10;
    for ($j = -9; $j < 10; $j++) {
        echo $i . ':' . $j . ":" . round($v
            + round($a1, $j + 1) + round($a2, $j + 1)
            - round($a1, $j) - round($a2, $j)
            + round($b1, $j + 1) + round($b2, $j + 1)
            - round($b1, $j) - round ($b2, $j),
            $j, PHP_ROUND_HALF_DOWN) . "\n";
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.