PHP округление чисел
Я не могу понять, как всегда округляться в PHP. ceil()
было бы очевидным выбором, но мне нужна та же функциональность, что и round()
обеспечивает своим вторым параметром "точность". Вот пример:
// Желаемый результат: 6250 эхо-раунд (6244,64, -2); // возвращает 6200 эхо-раунд (6244,64, -1); // возвращает 6240 echo ceil(6244.64) // возвращает 6245
Мне нужно, чтобы число всегда округлялось, чтобы можно было рассчитать равный делитель на основе параметров диаграммы.
6 ответов
Из комментария на 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);
}
Некоторые из этих ответов имеют проблемы с арифметикой с плавающей запятой, которые могут не сработать, как показано в этом ответе. Для пуленепробиваемого решения во всех случаях используйте эти:
/**
* Used to round up based on the decimal place, for example rounding up to the nearest penny
* http://stackru.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://stackru.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);
}
Как версия ceil(pow(10, $precision) * $value) / pow(10, $precision);
в некоторых случаях происходит сбой, например round_up(2.22, 2) дает неверный 2.23, как упоминалось здесь, поэтому я адаптировал это строковое решение для 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)
работает всегда, как и ожидалось, тогда все должно быть в порядке. Если вы обнаружите какой-то неудачный случай, дайте мне знать - мы должны искать другое решение:)
Вы можете разделить на 10, ceil(); а затем умножить на десять
Еще одно решение для ceil с точностью, без пауза, похоже, работает 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";
}
}