web-dev-qa-db-fra.com

PHP suppression de décimales sans arrondir

Je veux déposer des décimales sans arrondir. Par exemple, si j'ai 1,505, je veux supprimer la dernière décimale et la valeur doit être 1,50. Existe-t-il une telle fonction en PHP?

29
newbie

Vous avez besoin de floor () de cette manière:

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

Ou vous convertissez en entier:

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

De cette façon, il ne sera pas arrondi.

37
Rene Pot
$float = 1.505;

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

//outputs 1.50
12
IsisCode

C'est peut-être trop tard, mais voici une bonne approche:

    $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"  
    );
  • Le seul écueil dans cette approche peut être la nécessité d'utiliser une expression régulière (ce qui pourrait parfois entraîner une pénalité de performance).

Remarque: Il est assez difficile de trouver une approche native pour tronquer les décimales, et je pense qu'il n'est pas possible d'effectuer cela en utilisant sprintf et d'autres fonctions liées aux chaînes.

4
Telematica

Pour le faire avec précision pour les deux + ve et -ve nombres dont vous avez besoin, utilisez:
- la fonction php floor() pour les nombres + ve
- la fonction php ceil() pour les nombres -ve

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

la raison en est que floor() arrondit toujours le nombre bas, pas vers zéro.
c'est-à-dire floor() arrondit efficacement les nombres -ve vers une valeur absolue plus grande
par exemple floor(1.5) = 1 tandis que floor(-1.5) = -2

Par conséquent, pour la méthode de tronçonnage multiply by power, remove decimals, divide by power:
- floor() ne fonctionne que pour les nombres positifs
- ceil() ne fonctionne que pour les nombres négatifs

Pour tester cela, copiez le code suivant dans l'éditeur de http://phpfiddle.org/lite (ou similaire):

<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>';
?>
3
goredwards
$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; 

cela vous aidera à raccourcir la valeur flottante sans l'arrondir ..

2
Sujjad Ali

vous pouvez convertir 1.505 en type de données String et utiliser substring() pour tronquer le dernier caractère.
Et convertissez-le à nouveau en integer.

2
iChirag

Les réponses de RenaPot, IsisCode, goredwards ne sont pas correctes.

En raison du fonctionnement de float dans les ordinateurs (en général), float n'est pas précis.

Pour reproduire le problème:

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

Dans PHP en interne, 19.99 * 100 donne quelque chose comme 1998.999999999999999, qui lorsque nous faisons floor de cela, nous obtenons 1998.

Solution:

Solution 1: Utilisez la bibliothèque bcmath (suggérée par @SamyMassoud) si vous l'avez installée (certains serveurs d'hébergement partagé peuvent ne pas l'avoir installée par défaut). Ainsi:

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

Solution 2: Manipulation des chaînes (ma recommandation):

// 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"
1
evilReiko

Je sais que c'est une réponse tardive mais voici une solution simple. En utilisant l'exemple OP de 1.505, vous pouvez simplement utiliser ce qui suit pour atteindre 1.50.

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

Cela gère à la fois les valeurs positives et négatives sans se soucier de filtrer la fonction à utiliser et prête à corriger les résultats sans se soucier de ce que les autres fonctions pourraient faire avec la valeur.

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

Result: 1.50

Le sprintf est nécessaire pour obtenir exactement 2 décimales à afficher, sinon le résultat aurait été de 1,5 au lieu de 1,50.

0
Earnie Boyd

Nous pouvons utiliser les fonctions bc si elles sont disponibles:

echo bcadd(sprintf('%F', 5.445), '0', 2); // => 5.44
echo sprintf('%.2F', 5.445); // => 5.45
0
user2434435

Pour éviter d'utiliser le plafond, le sol et le rond, traitez-le simplement comme une ficelle et coupez-le si nécessaire. Cela évite tous les problèmes d'arrondi.

Le code ci-dessous recherche les 2 premiers chiffres après le point et les distingue. Ensuite, il recherche tous les chiffres qui suivent cela. Il remplace ensuite le tout par seulement les 2 chiffres qu'il a trouvés. Si le nombre ne correspond pas à la règle de remplacement, rien ne change.

Vous pouvez coller cela dans un appel de fonction et transmettre à la fonction le nombre et la quantité de nombres que vous souhaitez conserver après la décimale.

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