PHP сбрасывает десятичные дроби без округления - PullRequest
26 голосов
/ 31 января 2012

Я хочу отбрасывать десятичные дроби без округления.Например, если у меня есть 1.505, я хочу сбросить последний десятичный знак, и значение должно быть 1.50.Есть ли такая функция в PHP?

Ответы [ 10 ]

36 голосов
/ 31 января 2012

Вам нужно floor () таким образом:

$rounded = floor($float*100)/100;

Или вы приводите к целому числу:

$rounded = 0.01 * (int)($float*100);

Таким образом, оно не будет округляться.

12 голосов
/ 31 января 2012
$float = 1.505;

echo sprintf("%.2f", $float);

//outputs 1.50
4 голосов
/ 26 января 2015

Может быть, уже слишком поздно, но вот хороший подход:

    $getTruncatedValue = function( $value, $precision )
    {
        //Casts provided value
        $value = ( string )$value;

        //Gets pattern matches
        preg_match( "/(-+)?\d+(\.\d{1,".$precision."})?/" , $value, $matches );

        //Returns the full pattern match
        return $matches[0];            
    };

    var_dump
    (
        $getTruncatedValue(1.123,1),   //string(3) "1.1"
        $getTruncatedValue(1.345,2),   //string(4) "1.34"
        $getTruncatedValue(1.678,3),   //string(5) "1.678"
        $getTruncatedValue(1.90123,4)  //string(6) "1.9012"  
    );
  • Единственной ошибкой в ​​этом подходе может быть необходимость использования регулярного выражения (которое иногда может привести к снижению производительности).

Примечание: довольно сложно найти нативный подход к усечению десятичных дробей, и я думаю, что это невозможно сделать, используя sprintf и другие функции, связанные со строками.

3 голосов
/ 03 марта 2015

Чтобы сделать это точно для + ve и -ve номеров, вам необходимо использовать:
- функция php floor() для + ve номеров
-php ceil() функция для -ve чисел

function truncate_float($number, $decimals) {
    $power = pow(10, $decimals); 
    if($number > 0){
        return floor($number * $power) / $power; 
    } else {
        return ceil($number * $power) / $power; 
    }
}

причина этого в том, что floor() всегда округляет число вниз , а не к нулю.
т.е. floor() эффективно округляет -ve числа в сторону большего абсолютного значения
например, floor(1.5) = 1, тогда как floor(-1.5) = -2

Следовательно, для метода усечения multiply by power, remove decimals, divide by power:
- floor() работает только для положительных чисел
- ceil() работает только для отрицательных чисел

Чтобы проверить это, скопируйте следующий код в редактор http://phpfiddle.org/lite (или аналогичный):

<div>Php Truncate Function</div>
<br>
<?php
    function truncate_float($number, $places) {
        $power = pow(10, $places); 
        if($number > 0){
            return floor($number * $power) / $power; 
        } else {
            return ceil($number * $power) / $power; 
        }
    }

    // demo
    $lat = 52.4884;
    $lng = -1.88651;
    $lat_tr = truncate_float($lat, 3);
    $lng_tr = truncate_float($lng, 3);
    echo 'lat = ' . $lat . '<br>';
    echo 'lat truncated = ' . $lat_tr . '<br>';
    echo 'lat = ' . $lng . '<br>';
    echo 'lat truncated = ' . $lng_tr . '<br><br>';

    // demo of floor() on negatives
    echo 'floor (1.5) = ' . floor(1.5) . '<br>';
    echo 'floor (-1.5) = ' . floor(-1.5) . '<br>';
?>
2 голосов
/ 02 августа 2017
$num = 118.74999669307;
$cut = substr($num, 0, ((strpos($num, '.')+1)+2));`
// Cut the string from first character to a length of 2 past the decimal.
/ substr(cut what, start, ( (find position of decimal)+decimal itself)+spaces after decimal) )
echo $cut; 

это поможет вам сократить значение с плавающей точкой, не округляя его ..

2 голосов
/ 31 января 2012

вы можете преобразовать 1.505 в тип данных String и использовать substring() для усечения последнего символа.
И снова преобразовать его в integer.

1 голос
/ 11 апреля 2018

Ответы RenaPot , IsisCode , goredwards не верны.

Из-за того, как float работает в компьютерах (в целом), float не точен.

Чтобы повторить проблему:

floor(19.99 * 100);  // Outputs 1998 instead of 1999
floor( 5.10 * 100);  // Outputs  509 instead of  510

Внутри PHP внутри 19.99 * 100 получается что-то вроде 1998.999999999999999, что, когда мы делаем floor, мы получаем 1998.

Решение:

Решение 1: Используйте библиотеку bcmath (предложено @SamyMassoud), если она установлена ​​(некоторые серверы общего хостинга могут не устанавливать ее по умолчанию). Вот так:

//floor(19.99 * 100);// Original
floor(bcmul(19.99, 100));// Outputs 1999

Решение 2: Манипуляции со строками (моя рекомендация):

// Works with positive and negative numbers, and integers and floats and strings
function withoutRounding($number, $total_decimals) {
    $number = (string)$number;
    if($number === '') {
        $number = '0';
    }
    if(strpos($number, '.') === false) {
        $number .= '.';
    }
    $number_arr = explode('.', $number);

    $decimals = substr($number_arr[1], 0, $total_decimals);
    if($decimals === false) {
        $decimals = '0';
    }

    $return = '';
    if($total_decimals == 0) {
        $return = $number_arr[0];
    } else {
        if(strlen($decimals) < $total_decimals) {
            $decimals = str_pad($decimals, $total_decimals, '0', STR_PAD_RIGHT);
        }
        $return = $number_arr[0] . '.' . $decimals;
    }
    return $return;
}

// How to use:
withoutRounding(19.99, 2);// Return "19.99"
withoutRounding(1.505, 2);// Return "1.50"
withoutRounding(5.1, 2);// Return "5.10"
0 голосов
/ 13 апреля 2017

Мы можем использовать функции bc, если они доступны:

echo bcadd(sprintf('%F', 5.445), '0', 2); // => 5.44
echo sprintf('%.2F', 5.445); // => 5.45
0 голосов
/ 14 марта 2017

Я знаю, что это поздний ответ, но вот простое решение. Используя пример OP 1.505, вы можете просто использовать следующее, чтобы добраться до 1.50.

function truncateExtraDecimals($val, $precision) {
    $pow = pow(10, $precision);
    $precise = (int)($val * $pow);
    return (float)($precise / $pow); 
}

Это управляет как положительными, так и отрицательными значениями без необходимости фильтровать, какую функцию использовать, и позволяет корректировать результаты, не беспокоясь о том, что другие функции могут делать со значением.

$val = 1.509;
$truncated = sprintf('%.2f', truncateExtraDecimals($val, 2));
echo "Result: {$truncated}";

Result: 1.50

Параметр sprintf необходим, чтобы отображалось ровно 2 знака после запятой, иначе результат был бы 1,5 вместо 1,50.

0 голосов
/ 31 августа 2012

просто сделайте (int) $number;, чтобы получить целое число

...