Heim  >  Artikel  >  Backend-Entwicklung  >  Codeanalyse der Dezimalgenauigkeit in PHP

Codeanalyse der Dezimalgenauigkeit in PHP

不言
不言Original
2018-08-04 14:02:411957Durchsuche

Der Inhalt dieses Artikels befasst sich mit der Codeanalyse der Dezimalgenauigkeit in PHP. Ich hoffe, dass er für Freunde hilfreich ist.

Beim Runden auf zwei Dezimalstellen im Projekt sind Genauigkeitsprobleme aufgetreten:

$num = 0.99;
$num1 = round($num, 2);//0.98999999999999999
$num2 = floatval($num);//0.98999999999999999

Aktuelle Lösung:

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

Testergebnisse:

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

Ungefähr gleich 57 Wir können das Problem analysieren:

Darstellung von Gleitkommazahlen (IEEE 754: IEEE Binary Floating Point Arithmetic Standard):

Gleitkommazahlen unter Verwendung einer 64-Bit-Länge (doppelte Genauigkeit) als Beispiel: wird durch 1 Vorzeichenbit (E), 11 Exponentenbits (Q) und 52 Mantissen (M) (insgesamt 64 Bits) dargestellt.

Vorzeichenbit: Das höchste Bit gibt das Vorzeichen von an In den Daten bedeutet 0 eine positive Zahl, 1 bedeutet eine negative Zahl.

Exponentenbit: Stellt die Potenz der Daten mit Basis 2 dar, der Exponent wird durch den Offset-Code dargestellt

Mantisse: Stellt die signifikanten Stellen nach dem Dezimalpunkt der Daten dar

0,58 für die binäre Darstellung. Beispielsweise ist es ein unendlich langer Wert:

Die binäre Darstellung von 0,58 ist grundsätzlich (52 Bits): 0010100011110101110000101000111101011100001010001111

Die binäre Darstellung von. 0,57 ist im Grunde ( 52 Bits) ist: 001000111101011100001010001111010111000010100011110

Und die Binärzahlen der beiden, wenn sie nur mit diesen 52 Bits berechnet werden, sind:

  0,58 -->. 0,5799999 999999996

0,57 --> 0,5699999999 999999

Das Ergebnis von 0,58 * 100 ist also: 57,999999999, umgewandelt in eine ganze Zahl: 57

Für die binäre Darstellung von Gleitkommazahlen können Sie sich auf Folgendes beziehen: Binäre Darstellung von Gleitkommazahlen Punktzahlen

Ähnlich wie:

(0.1 + 0.7) == 0.8//false

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

Also Fazit:

Glauben Sie also niemals, dass das Gleitkommaergebnis bis zur letzten Ziffer genau ist, und vergleichen Sie niemals zwei Gleitkommazahlen Punktzahlen, um zu sehen, ob sie gleich sind. Wenn Sie wirklich eine höhere Präzision benötigen, sollten Sie mathematische Funktionen mit beliebiger Präzision oder GMP-Funktionen verwenden

Es wird empfohlen, hochpräzise Funktionen zu verwenden:

Hochpräzise Funktionen

  • bcadd – Addition von 2 Zahlen beliebiger Genauigkeit

  • bccomp – Vergleicht zwei Zahlen beliebiger Genauigkeit

  • bcp – Berechnen Sie die Division von 2 Zahlen beliebiger Genauigkeit

  • bcmod – Modulo einer Zahl beliebiger Genauigkeit

  • bcmul – Multiplikationsberechnung von 2 Zahlen mit beliebiger Genauigkeit

  • bcpow – die Potenz einer Zahl mit beliebiger Genauigkeit

  • bcpowmod – Erhöhen einer beliebigen Präzisionszahl auf eine andere, reduziert um einen angegebenen Modul

  • bcscale – Legen Sie die Standardanzahl der Dezimalstellen für alle bc-Mathefunktionen fest

  • bcsqrt – die Quadratwurzel einer Zahl mit beliebiger Genauigkeit

  • bcsub – die Subtraktion von 2 Zahlen mit beliebiger Genauigkeit

Verwenden Sie hochpräzise Funktionen, um Rundungen zu erreichen:

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

Empfohlene verwandte Artikel:

Parsen von AES-verschlüsselten Dateien in PHP (mit Code)

Code für Post-Methode anfordern und Methode in Curl von PHP abrufen

Über PHP Middle Key Content Analysis

Das obige ist der detaillierte Inhalt vonCodeanalyse der Dezimalgenauigkeit in PHP. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn