Как округлить / потолок / пол bcmath число в PHP?
Есть ли какая-либо библиотечная функция для этой цели, поэтому я не делаю это вручную и рискую закончить в TDWTF?
echo ceil(31497230840470473074370324734723042.6);
// Expected result
31497230840470473074370324734723043
// Prints
<garbage>
2 ответа
Это будет работать для вас:
$x = '31497230840470473074370324734723042.9';
bcscale(100);
var_dump(bcFloor($x));
var_dump(bcCeil($x));
var_dump(bcRound($x));
function bcFloor($x)
{
$result = bcmul($x, '1', 0);
if ((bccomp($result, '0', 0) == -1) && bccomp($x, $result, 1))
$result = bcsub($result, 1, 0);
return $result;
}
function bcCeil($x)
{
$floor = bcFloor($x);
return bcadd($floor, ceil(bcsub($x, $floor)), 0);
}
function bcRound($x)
{
$floor = bcFloor($x);
return bcadd($floor, round(bcsub($x, $floor)), 0);
}
В основном это находит flooy, умножаясь на один с нулевой точностью.
Затем он может сделать ceil / round, вычтя это из суммы, вызвав встроенные функции, затем добавив результат обратно на
Редактировать: исправлено для -ve номеров
ОБНОВЛЕНИЕ: Смотрите мой улучшенный ответ здесь: Как потолочные, напольные и круглые числа bcmath? ,
Эти функции, кажется, имеют больше смысла, по крайней мере для меня:
function bcceil($number)
{
if ($number[0] != '-')
{
return bcadd($number, 1, 0);
}
return bcsub($number, 0, 0);
}
function bcfloor($number)
{
if ($number[0] != '-')
{
return bcadd($number, 0, 0);
}
return bcsub($number, 1, 0);
}
function bcround($number, $precision = 0)
{
if ($number[0] != '-')
{
return bcadd($number, '0.' . str_repeat('0', $precision) . '5', $precision);
}
return bcsub($number, '0.' . str_repeat('0', $precision) . '5', $precision);
}
Они поддерживают отрицательные числа и аргумент точности для функции bcround().
Некоторые тесты:
assert(bcceil('4.3') == ceil('4.3')); // true
assert(bcceil('9.999') == ceil('9.999')); // true
assert(bcceil('-3.14') == ceil('-3.14')); // true
assert(bcfloor('4.3') == floor('4.3')); // true
assert(bcfloor('9.999') == floor('9.999')); // true
assert(bcfloor('-3.14') == floor('-3.14')); // true
assert(bcround('3.4', 0) == number_format('3.4', 0)); // true
assert(bcround('3.5', 0) == number_format('3.5', 0)); // true
assert(bcround('3.6', 0) == number_format('3.6', 0)); // true
assert(bcround('1.95583', 2) == number_format('1.95583', 2)); // true
assert(bcround('5.045', 2) == number_format('5.045', 2)); // true
assert(bcround('5.055', 2) == number_format('5.055', 2)); // true
assert(bcround('9.999', 2) == number_format('9.999', 2)); // true
Хорошо, для моей высокоточной библиотеки Money, которая в настоящее время находится на сотнях производственных площадок, мне пришлось полностью переписать эту функциональность bcround. Ничего из того, что я нашел во всем Интернете, не было в порядке.
Вот что я придумал:
/**
* Based off of https://stackru.com/a/1653826/430062
* Thanks, [Alix Axel](https://stackru.com/users/89771/alix-axel)!
*
* @param $number
* @param int $precision
* @return string
*/
function bcround($number, $precision = BCMathCalcStrategy::PRECISION)
{
if (strpos($number, '.') !== false) {
if ($number[0] != '-') return bcadd($number, '0.' . str_repeat('0', $precision) . '5', $precision);
return bcsub($number, '0.' . str_repeat('0', $precision) . '5', $precision);
}
// Pad it out to the desired precision.
return number_format($number, $precision);
}