PHP Как мне округлить до двух десятичных знаков?
Мне нужно округлить десятичную дробь в PHP до двух десятичных знаков, чтобы:
49.955
становится...
49.95
Я попытался number_format, но это просто округляет значение до 49,96. Я не могу использовать substr, потому что число может быть меньше (например, 7,950). Я не смог найти ответ на этот вопрос до сих пор.
Любая помощь высоко ценится.
13 ответов
К сожалению, ни один из предыдущих ответов (включая принятый) не работает для всех возможных входов.
1) sprintf('%1.'.$precision.'f', $val)
Сбой с точностью 2: 14.239 должен вернуть 14.23 (но в этом случае возвращает 14.24).
2) floatval(substr($val, 0, strpos($val, '.') + $precision + 1))
Сбой с точностью 0: 14 должен вернуть 14 (но в этом случае возвращает 1)
3) substr($val, 0, strrpos($val, '.', 0) + (1 + $precision))
Сбой с точностью 0: -1 должен вернуть -1 (но в этом случае возвращает '-')
4) floor($val * pow(10, $precision)) / pow(10, $precision)
Хотя я использовал это широко, недавно я обнаружил недостаток в этом; это не подходит для некоторых значений тоже. С точностью до 2: 2.05 должен возвращать 2.05 (но в этом случае возвращает 2.04!!)
Пока что единственный способ пройти все мои тесты - это, к сожалению, использовать манипуляции со строками. Мое решение на основе рационального босса одно:
function floorDec($val, $precision = 2) {
if ($precision < 0) { $precision = 0; }
$numPointPosition = intval(strpos($val, '.'));
if ($numPointPosition === 0) { //$val is an integer
return $val;
}
return floatval(substr($val, 0, $numPointPosition + $precision + 1));
}
Эта функция работает с положительными и отрицательными числами, а также с любой необходимой точностью.
РЕДАКТИРОВАТЬ: Вы можете найти рабочий пример здесь: http://codepad.viper-7.com/ZGprQJ, но в настоящее время это мертвая ссылка.
Вот хорошая функция, которая делает трюк без использования строковых функций:
<?php
function floorp($val, $precision)
{
$mult = pow(10, $precision); // Can be cached in lookup table
return floor($val * $mult) / $mult;
}
print floorp(49.955, 2);
?>
Другой вариант - вычесть дробь перед округлением:
function floorp($val, $precision)
{
$half = 0.5 / pow(10, $precision); // Can be cached in a lookup table
return round($val - $half, $precision);
}
Я думаю, что есть довольно простой способ добиться этого:
$rounded = bcdiv($val, 1, $precision);
Вот рабочий пример. Вам нужно установить BCMath, но я думаю, что он обычно связан с установкой PHP.:) Вот документация.
function roundDown($decimal, $precision)
{
$fraction = substr($decimal - floor($decimal), 2, $precision); //calculates the decimal places to $precision length
$newDecimal = floor($decimal). '.' .$fraction; // reconstructs decimal with new # of decimal places
return floatval($newDecimal);
}
echo roundDown(345.8768378, 5); // OUTPUT: 345.87683
Эта функция работает с положительными и отрицательными числами.
Пример кода здесь: http://codepad.org/RAOyBCuY
Умножьте ваш ввод на 100, floor(), затем разделите результат на 100.
Попробуйте round()
функция
Как это: round($num, 2, PHP_ROUND_HALF_DOWN);
Для всех, кто в этом нуждается, я использовал небольшой трюк, чтобы преодолеть неисправность математических функций, например, floor или intval(9,7*100)=969 странно.
function floor_at_decimals($amount, $precision = 2)
{
$precise = pow(10, $precision);
return floor(($amount * $precise) + 0.1) / $precise;
}
Таким образом, добавление небольшого количества (которое в любом случае будет затоплено) как-то решает проблему.
Ты можешь использовать:
$num = 49.9555;
echo substr($num, 0, strpos($num, '.') + 3);
function floorToPrecision($val, $precision = 2) {
return floor(round($val * pow(10, $precision), $precision)) / pow(10, $precision);
}
Если вы хотите округлить десятичную дробь вниз только тогда, когда последняя ее часть равна 5 или ниже, тогда лучшим решением будет использование:
round(4.955,2,PHP_ROUND_HALF_DOWN);
Теперь, если вы хотите всегда округлять десятичные дроби вниз и по-прежнему контролировать количество десятичных дробей, лучшее решение:
round(floor(4.957*100)/100,2)
Также учтите, что число "100" должно масштабироваться вместе с десятичным знаком "2". Например, если вы хотите 4 десятичных знака, вам придется умножить на 10000 и разделить на 10000, чтобы вы потеряли только числа после этой точки.
Альтернативное решение с использованием регулярных выражений, которое должно работать для всех положительных или отрицательных чисел, целых или с десятичными:
if (preg_match('/^-?(\d+\.?\d{1,2})\d*$/', $originalValue, $matches)){
$roundedValue = $matches[1];
} else {
throw new \Exception('Cannot round down properly '.$originalValue.' to two decimal places');
}
Основываясь на ответах @huysentruitw и @Alex, я придумал следующую функцию, которая должна помочь.
Он проходит все тесты, данные в ответе Алекса (почему это невозможно), и основывается на ответе huysentruitw.
function trim_number($number, $decimalPlaces) {
$delta = (0 <=> $number) * (0.5 / pow(10, $decimalPlaces));
$result = round($number + $delta, $decimalPlaces);
return $result ?: 0; // get rid of negative zero
}
Ключ состоит в том, чтобы добавить или вычесть дельту на основе исходного числового знака, чтобы поддерживать обрезку также отрицательных чисел. И последнее - избавиться от отрицательных нулей (-0), поскольку это может быть нежелательным поведением.
Ссылка на "тестовую" площадку.
РЕДАКТИРОВАТЬ: похоже, что bcdiv - это путь.
// round afterwards to cast 0.00 to 0
// set $divider to 1 when no division is required
round(bcdiv($number, $divider, $decimalPlaces), $decimalPlaces);
sprintf("%1.2f",49.955) //49.95
если вам нужно обрезать десятичные дроби без округления - это не подходит, потому что оно будет работать правильно до 49,955 в конце, если число больше, например 49,957, оно будет округлено до 49,96
Мне кажется, что ответ Лтха с полом наиболее универсален.
Ты пробовал round($val,2)
?
Больше информации о round()
функция