2010-01-15 2 views
2

Я не могу понять, как всегда округлить в PHP. ceil() был бы очевидным выбором, но мне нужна такая же функциональность, что и round() имеет второй параметр «точность». Вот пример:PHP округления чисел

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

Мне нужен номер, чтобы всегда округлять вверх так, что я могу вычислить равный делитель на основе параметров для диаграммы.

ответ

5

С комментарием на 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); 
} 
+0

Я думаю, что порядок работы перемешивается, вам нужно разделить, прежде потолке, а затем умножить, а не наоборот, нет? – nicolaskruchten

+0

@njk: потолок (6244,64, -1) дает желаемый результат 6250. Обратите внимание, что точность в этом случае является отрицательной. –

+0

Это вернет true: 'потолок (77.4, 2) === 77.41'. Функция сломана. – bzeaman

0

Можно разделить на 10, CEIL(); а затем умножить на десять

-1

еще одно решение с точностью потолке, не бух, это выглядит как произведения 9 цифр с обеих сторон:

$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"; 
    } 
} 
0

В версии ceil(pow(10, $precision) * $value)/pow(10, $precision); терпит неудачу в некоторых случаях, например, round_up (2.22, 2) дает неверный 2.23, как указано here, поэтому я применил этот string solution for round_down() к нашей проблеме round_up(). Это результат (отрицательная точность не распространяется):

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

Я не знаю, что это пуленепробиваемое, но, по крайней мере, он удаляет упомянутые выше провал. Я не делал анализ с двоичным-десятичным-математическим анализом, но если $floorValue + pow(10, 0 - $precision) работает всегда, как и ожидалось, тогда все должно быть в порядке. Если вы найдете какой-то неудачный случай, дайте мне знать - мы должны искать другое решение :)

0

Некоторые из этих ответов имеют проблемы с арифметикой с плавающей запятой, которая может выйти из строя, как показано в this answer. Для пуленепробиваемого решения во всех случаях использовать их:

/** 
* 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); 
} 
Смежные вопросы