Analyse du code de la précision décimale en php

不言
Libérer: 2023-04-03 15:44:02
original
2001 Les gens l'ont consulté

Le contenu de cet article concerne l'analyse du code de précision décimale en PHP. Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer.

Problèmes de précision rencontrés lors de l'arrondi à deux décimales dans le projet :

$num = 0.99;
$num1 = round($num, 2);//0.98999999999999999
$num2 = floatval($num);//0.98999999999999999
Copier après la connexion

Solution actuelle :

sprintf("%.2f", round($money, 2));//会自动四舍五入
echo substr(sprintf("%.3f",$n), 0, -1);//不四舍五入
Copier après la connexion

Résultats des tests :

var_dump(json_encode(round(0.99 ,2)));//0.98999999999999999
var_dump(round(0.99 ,2));//0.99

$f = 0.58;    
var_dump(intval($f * 100));//57
Copier après la connexion

Concernant la problématique de égal à 57, on peut l'analyser :

Représentation des nombres à virgule flottante (IEEE 754 : IEEE Binary Floating Point Arithmetic Standard) :

Nombres à virgule flottante, avec un longueur de 64 bits (Double précision) à titre d'exemple, il sera représenté par 1 bit de signe (E), 11 bits d'exposant (Q) et 52 bits de mantisse (M) (un total de 64 bits

<). 🎜> Bit de signe : le bit le plus élevé représente les données Le positif et le négatif de , 0 représente un nombre positif et 1 représente un nombre négatif.

Bit exposant : représente la puissance des données en base 2, l'exposant est représenté par un code offset

Mantisse : représente les chiffres significatifs après la virgule décimale

0,58 pour la représentation binaire Par exemple, c'est une valeur infiniment longue :

La représentation binaire de 0,58 est essentiellement (52 bits) : 0010100011110101110000101000111101011100001010001111

La représentation binaire de 0 .57 est essentiellement ( 52 bits) est : 001000111101011100001010001111010111000010100011110

Et les nombres binaires des deux, s'ils sont calculés uniquement par ces 52 bits, sont :

  0,58 --> 999999996

0,57 -- > 0,5699999999 999999

Ainsi, le résultat de 0,58 * 100 sera : 57,999999999, converti en entier : 57

Pour la représentation binaire des nombres à virgule flottante, vous pouvez vous référer à : Représentation binaire de nombres à virgule flottante

Similaire à :

(0.1 + 0.7) == 0.8//false

floor((0.1+0.7)*10)//7 
//内部结果可能是:7.9999999999
//所以:不可能精确的用有限位数表达某些十进制分数
1/3=3.33333333333
//而3.333333333333333*3,却不是1
Copier après la connexion
Donc conclusion :

Ne croyez donc jamais que le résultat d'un nombre à virgule flottante est précis jusqu'au dernier chiffre, et ne comparez jamais deux nombres à virgule flottante pour voir s'ils sont égaux. Si vous avez vraiment besoin d'une plus grande précision, vous devez utiliser des fonctions mathématiques de précision arbitraire ou des fonctions gmp

Il est recommandé d'utiliser des fonctions de haute précision :

Fonctions de haute précision

  • bcadd — Ajout de 2 nombres à précision arbitraire

  • bccomp — Compare deux nombres à précision arbitraire

  • bcp — Calculer la division de 2 nombres à précision arbitraire

  • bcmod — Modulo un nombre à précision arbitraire

  • bcmul — Calcul de multiplication de 2 nombres de précision arbitraires

  • bcpow — la puissance d'un nombre de précision arbitraire

  • bcpowmod — Élève un nombre de précision arbitraire à un autre, réduit d'un module spécifié

  • bcscale — Définit le nombre de décimales par défaut pour toutes les fonctions mathématiques bc

  • bcsqrt — la racine carrée d'un nombre à précision arbitraire

  • bcsub — la soustraction de 2 nombres à précision arbitraire

Utiliser des fonctions de haute précision pour réaliser des arrondis :

    function getBcRound($number, $precision = 0)
    {
        $precision = ($precision < 0)
                   ? 0
                   : (int) $precision;
        if (strcmp(bcadd($number, &#39;0&#39;, $precision), bcadd($number, &#39;0&#39;, $precision+1)) == 0) {
            return bcadd($number, &#39;0&#39;, $precision);
        }
        if (getBcPresion($number) - $precision > 1) {
            $number = getBcRound($number, $precision + 1);
        }
        $t = &#39;0.&#39; . str_repeat(&#39;0&#39;, $precision) . &#39;5&#39;;
        return $number < 0
               ? bcsub($number, $t, $precision)
               : bcadd($number, $t, $precision);
    }
    
    function getBcPresion($number) {
        $dotPosition = strpos($number, &#39;.&#39;);
        if ($dotPosition === false) {
            return 0;
        }
        return strlen($number) - strpos($number, &#39;.&#39;) - 1;
    }
    
    $money = getBcRound(0.99, 2);
Copier après la connexion
Articles connexes recommandés :

Analyse de fichiers cryptés AES en PHP (avec code)

Demander des codes pour le mode publication et obtenir le mode dans curl de php

À propos de l'analyse du contenu des touches centrales PHP

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal