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.

Torez
  • 1,902
  • 7
  • 25
  • 39

6 Answers6

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);
}
Mark Byers
  • 811,555
  • 193
  • 1,581
  • 1,452
3

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);
}
Nico Westerdale
  • 2,147
  • 1
  • 24
  • 31
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 :)

Mojo
  • 187
  • 3
  • 14
  • 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 – Tama Apr 09 '21 at 19:59
0

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

mirosval
  • 6,671
  • 3
  • 32
  • 46
0
echo 10*ceil($number/10);
nicolaskruchten
  • 26,384
  • 8
  • 83
  • 101
-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";
    }
}
loshad vtapkah
  • 429
  • 4
  • 11