Ответ 1
Это может работать: floor($number * 100) / 100
Мне нужно округлить десятичное число в PHP до двух знаков после запятой, чтобы:
49.955
становится...
49.95
Я пробовал number_format, но это просто округляет значение до 49.96. Я не могу использовать substr, потому что число может быть меньше (например, 7.950). Мне пока не удалось найти ответ.
Любая помощь очень ценится.
Это может работать: floor($number * 100) / 100
Вот хорошая функция, которая делает трюк без использования строковых функций:
<?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);
}
К сожалению, ни один из предыдущих ответов (включая принятый) не работает для всех возможных входных данных.
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));
}
Эта функция работает с положительными и отрицательными числами, а также с любой необходимой точностью.
Умножьте свой ввод на 100, floor(), затем разделите результат на 100.
Попробуйте round()
функция
Пример: round($num, 2, PHP_ROUND_HALF_DOWN);
function roundDown($decimal, $precision)
{
$sign = $decimal > 0 ? 1 : -1;
$base = pow(10, $precision);
return floor(abs($decimal) * $base) / $base * $sign;
}
// Examples
roundDown(49.955, 2); // output: 49.95
roundDown(-3.14159, 4); // output: -3.1415
roundDown(1000.000000019, 8); // output: 1000.00000001
Эта функция работает с положительными и отрицательными десятичными знаками с любой точностью.
Пример кода здесь: http://codepad.org/1jzXjE5L
function floorToPrecision($val, $precision = 2) {
return floor(round($val * pow(10, $precision), $precision)) / pow(10, $precision);
}
Я думаю, что есть довольно простой способ добиться этого:
$rounded = bcdiv($val, 1, $precision);
Вот рабочий пример. Вам нужно установить BCMath, но я думаю, что он обычно связан с установкой PHP. :) Вот документация.
Вы можете использовать PHP-функцию bcdiv.
bcdiv(49.955, 1, 2)
Использовать форматированный вывод
sprintf("%1.2f",49.955) //49.95
Вы можете использовать:
$num = 49.9555;
echo substr($num, 0, strpos($num, '.') + 3);
Альтернативное решение с использованием регулярного выражения, которое должно работать для всех положительных или отрицательных чисел, целых или десятичных знаков:
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');
}
Если вы хотите округлить десятичную дробь вниз только тогда, когда последняя ее часть равна 5 или ниже, тогда лучшим решением будет использование:
round(4.955,2,PHP_ROUND_HALF_DOWN);
Теперь, если вы хотите всегда округлять десятичные дроби вниз и по-прежнему контролировать количество десятичных дробей, лучшее решение:
round(floor(4.957*100)/100,2)
Также учтите, что число "100" должно масштабироваться вместе с десятичным знаком "2". Например, если вы хотите 4 десятичных знака, вам придется умножить на 10000 и разделить на 10000, чтобы вы потеряли только числа после этой точки.
Основываясь на ответах @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.95 5 в конце, если число больше, например, 49.95 7 он будет округлен до 49,96
Мне кажется, что ответ Lght с полом является самым универсальным.
Как насчет этого?
$value = 49.955;
echo intval( $value * 100 ) / 100;
Вы попробовали round($val,2)
?
Подробнее о round()
функция