PHP 去掉小数而不舍入

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9079158/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-26 06:07:16  来源:igfitidea点击:

PHP dropping decimals without rounding up

phpdecimalrounding

提问by newbie

I want to drop off decimals without rounding up. For example if I have 1.505, I want to drop last decimal and value should be 1.50. Is there such a function in PHP?

我想去掉小数而不四舍五入。例如,如果我有 1.505,我想去掉最后一个小数点,值应该是 1.50。PHP中有这样的函数吗?

回答by Rene Pot

You need floor()in this way:

你需要floor()以这种方式:

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

Or you cast to integer:

或者您转换为整数:

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

This way it will not be rounding up.

这样它就不会四舍五入。

回答by IsisCode

$float = 1.505;

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

//outputs 1.50

回答by goredwards

To do this accurately for both +ve and-ve numbers you need use:
- the php floor()function for +ve numbers
- the php ceil()function for -ve numbers

要对 +ve-ve 数字准确地执行此操作,您需要使用:
- floor()+ve 数字
的 phpceil()函数- -ve 数字的 php函数

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

the reason for this is that floor()always rounds the number down, not towards zero.
ie floor()effectively rounds -ve numbers towards a larger absolute value
eg floor(1.5) = 1while floor(-1.5) = -2

这样做的原因是floor()总是将数字向下舍入,而不是向零舍入。
floor()有效地将 -ve 数字向更大的绝对值四舍五入,
例如floor(1.5) = 1whilefloor(-1.5) = -2

Therefore, for the multiply by power, remove decimals, divide by powertruncate method :
- floor()only works for positive numbers
- ceil()only works for negative numbers

因此,对于multiply by power, remove decimals, divide by power截断方法:
-floor()仅适用于正数
-ceil()仅适用于负数

To test this, copy the following code into the editor of http://phpfiddle.org/lite(or similar):

要对此进行测试,请将以下代码复制到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>';
?>

回答by Telematica

Maybe it's too late, but here's a good approach:

也许为时已晚,但这里有一个好方法:

    $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"  
    );
  • The only pitfall in this approach may be the need to use a Regular Expression (which sometimes could bring a performance penalty).
  • 这种方法的唯一缺陷可能是需要使用正则表达式(有时会带来性能损失)。

Note: It's quite hard to find a native approach to truncate decimals, and I think it's not possible to perform that using sprintf and other string-related functions.

注意:很难找到截断小数的本机方法,我认为使用 sprintf 和其他与字符串相关的函数无法执行该方法。

回答by evilReiko

The answers of RenaPot, IsisCode, goredwardsare not correct.

RenaPotIsisCodegoredwards的答案是不正确的。

Because of how float works in computers (in general), float is not accurate.

由于浮点数在计算机中的工作方式(一般而言),浮点数不准确。

To replicate the issue:

要复制问题:

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

Within PHP internally, 19.99 * 100results in something like 1998.999999999999999, which when we do floorof that, we get 1998.

在 PHP 内部,19.99 * 100结果类似于1998.999999999999999,当我们这样做floor时,我们得到1998.

Solution:

解决方案:

Solution 1:Use bcmathlibrary (Suggested by @SamyMassoud) if you have it installed (some shared hosting servers may not have it installed by default). Like so:

解决方法1:使用bcmath时库(由@SamyMassoud建议)如果你安装了它(一些共享托管服务器可能没有它安装在默认情况下)。像这样:

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

Solution 2:String manipulation (my recommendation):

解决方案 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"

回答by Sujjad A

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

this will help you shorten the float value without rounding it..

这将帮助您缩短浮点值而不对其进行四舍五入。

回答by iChirag

you can convert 1.505to String data type and make use of substring()to truncate last character.
And again convert it in integer.

您可以转换1.505为 String 数据类型并使用substring()截断最后一个字符。
并再次将其转换为integer.

回答by paovivi

Use the PHP native function bcdiv

使用 PHP 原生函数bcdiv

echo bcdiv(2.56789, 1, 2);  // 2.56

回答by Adam Whateverson

To avoid using ceil, floor and round, just treat it as a string and cut it if necessary. This avoids all the rounding issues.

为避免使用 ceil、floor 和 round,只需将其视为字符串并在必要时将其剪断即可。这避免了所有的舍入问题。

The code below looks for the first 2 numbers after the dot and singles them out. Then it looks for any numbers that trail that. It then replaces the entire thing with only the 2 numbers it found. If number doesn't match the replace rule, nothing changes.

下面的代码查找点后的前 2 个数字并将它们挑出来。然后它会查找任何跟在它后面的数字。然后它只用它找到的 2 个数字替换整个事物。如果 number 与替换规则不匹配,则不会发生任何变化。

You could stick this in a function call and pass the function the number and the quantity of numbers you want to keep after the decimal place.

你可以把它放在一个函数调用中,并将你想要保留在小数位后的数字和数字数量传递给函数。

    // Shorten number to 2 decimal places without rounding
    $num = 2213.145;
    $num = floatval(preg_replace("/\.([0-9]{2})[0-9]{0,99}/",".",$num));

回答by Earnie Boyd

I know this is a late answer but here is a simple solution. Using the OP example of 1.505 you can simply use the following to get to 1.50.

我知道这是一个迟到的答案,但这里有一个简单的解决方案。使用 1.505 的 OP 示例,您可以简单地使用以下内容来获得 1.50。

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

This manages both positive and negative values without the concern to filter which function to use and lends to correct results without the worry about what other functions might do with the value.

这可以管理正值和负值,而无需担心过滤要使用的函数并提供正确的结果,而无需担心其他函数可能会对值做什么。

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

Result: 1.50

The sprintf is needed to get exactly 2 decimals to display otherwise the Result would have been 1.5 instead of 1.50.

sprintf 需要精确显示 2 位小数,否则结果将是 1.5 而不是 1.50。