PHP Как мне округлить до двух десятичных знаков?

Мне нужно округлить десятичную дробь в PHP до двух десятичных знаков, чтобы:

49.955

становится...

49.95

Я попытался number_format, но это просто округляет значение до 49,96. Я не могу использовать substr, потому что число может быть меньше (например, 7,950). Я не смог найти ответ на этот вопрос до сих пор.

Любая помощь высоко ценится.

13 ответов

Решение

Это может работать: floor($number * 100) / 100

К сожалению, ни один из предыдущих ответов (включая принятый) не работает для всех возможных входов.

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.

Вы можете использовать PHP-функцию bcdiv.

bcdiv(49.955, 1, 2)

Попробуйте 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;
}

Таким образом, добавление небольшого количества (которое в любом случае будет затоплено) как-то решает проблему.

Используйте форматированный вывод

sprintf("%1.2f",49.955) //49.95

DEMO

Ты можешь использовать:

$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);

Как насчет этого?

$value = 49.955;

echo intval( $value * 100 ) / 100;

Вот демо

sprintf("%1.2f",49.955) //49.95

если вам нужно обрезать десятичные дроби без округления - это не подходит, потому что оно будет работать правильно до 49,955 в конце, если число больше, например 49,957, оно будет округлено до 49,96
Мне кажется, что ответ Лтха с полом наиболее универсален.

Ты пробовал round($val,2)?

Больше информации о round() функция

Другие вопросы по тегам