In der Sprache C und C# werden Daten vom Typ Gleitkommazahl mit einfacher Genauigkeit (Float) und Typ mit doppelter Genauigkeit (Double Float) gespeichert und belegen 32 Bit. Doppelte Daten belegen 64 Bits, wenn wir eine Variable float f= 2,25f deklarieren. Wäre die Welt nicht im Chaos, wenn es zufällig zugewiesen würde? Tatsächlich entsprechen sowohl Float als auch Double den IEEE-Spezifikationen in Bezug auf die Speichermethoden, während Double R64.53 entspricht.
Unabhängig davon, ob es sich um einfache oder doppelte Genauigkeit handelt, ist der Speicher in drei Teile unterteilt:
Vorzeichenbit (Sign): 0 steht für positiv, 1 steht für negativ
Exponentenbit ( Exponent): Wird zum Speichern exponentieller Daten in wissenschaftlicher Notation verwendet und verwendet eine Verschiebungsspeicherung.
Mantissenteil (Mantisse): Mantissenteil
Dieser Artikel stellt hauptsächlich PHP-Gleitkommazahlen vor. Zusammenfassung der Präzisionsprobleme Der Artikel konzentriert sich auf das Problem des PHP-Gleitkomma-Präzisionsverlusts. In drei Absätzen werden die Ursachen und Lösungen für dieses Problem auf unterschiedliche Weise erläutert.
1. PHP Das Problem von Gleitkomma-Präzisionsverlust
Schauen Sie sich zunächst den folgenden Code an:
Der Code lautet wie folgt:
$f = 0.57; echo intval($f * 100); //56
Das Ergebnis kann etwas sein Überraschenderweise folgt PHP der doppelten Präzision von IEEE 754:
Gleitkommazahlen mit doppelter 64-Bit-Präzision werden durch 1 Vorzeichenbit (E), 11 Exponentenbits (Q) und 52 Mantissen (M) dargestellt ) (insgesamt 64 Bit).
Vorzeichenbit: Das höchste Bit stellt das Vorzeichen der Daten dar, 0 steht für eine positive Zahl und 1 steht für eine negative Zahl.
Exponentenbit: stellt die Potenz der Daten zur Basis 2 dar, und der Exponent wird durch einen Offset-Code dargestellt
Mantisse: stellt die signifikanten Nachkommastellen der Daten dar.
Nehmen wir Schauen Sie sich an, wie Dezimalzahlen binär dargestellt werden:
Mit 2 multiplizieren und aufrunden, in der richtigen Reihenfolge anordnen, d. h. den Dezimalteil mit 2 multiplizieren, dann den Teil Ganzzahl nehmen, weitermachen Multiplizieren Sie den verbleibenden Dezimalteil mit 2, nehmen Sie dann den ganzzahligen Teil und den verbleibenden Dezimalteil. Der Teil wird erneut mit 2 multipliziert, bis der Dezimalteil erhalten wird. Wenn jedoch eine Dezimalzahl wie 0,57 auf diese Weise multipliziert wird, kann der Dezimalteil nicht multipliziert werden sei 0. Die dezimale Darstellung signifikanter Ziffern ist binär unendlich.
Die binäre Darstellung von 0,57 ist grundsätzlich (52 Bits): 0010001111010111000010100011110101110000101000111101
Wenn es nur 52 Bits gibt, ist 0,57 =》0,569999999 999 99995
Es ist nicht schwer, das Unerwartete zu sehen Ergebnisse oben, oder?
2. Präzisionsproblem von PHP-Gleitkommazahlen
Sehen wir uns zunächst das Problem an:
Der Code lautet wie folgt:
$f = 0.58; var_dump(intval($f * 100)); //为啥输出57
Ich glaube, dass viele Studierende solche Fragen hatten.
Für das konkrete Prinzip können Sie einen Artikel von „Brother Bird“ lesen, in dem es eine ausführliche Erklärung gibt: Eine FAQAntwort auf PHP-Gleitkommazahlen
Also Wie vermeide ich das? Was für ein Problem?
Es gibt viele Möglichkeiten, hier sind zwei:
1. sprintf
Der Code lautet wie folgt:
substr(sprintf("%.10f", ($a/ $b)), 0, -7);
2. rund (Hinweis Wird gerundet)
Der Code lautet wie folgt:
round($a/$b, 3);
Oder wenn Sie einen besseren Weg haben, können Sie auch eine Nachricht hinterlassen und es mir sagen.
3. Antworten auf eine häufig gestellte Frage zu PHP-Gleitkommazahlen
Zu PHP-Gleitkommazahlen habe ich bereits einen Artikel geschrieben: Was Sie über PHP-Gleitkommazahlen wissen sollten Punktzahlen (Alles „gefälscht“ über den Float in PHP)
Allerdings habe ich damals eine Sache übersehen, nämlich die Antwort auf die folgende häufige Frage:
Der Code lautet wie folgt:
<?php $f = 0.58; var_dump(intval($f * 100)); //为啥输出57 ?>
Warum ist die Ausgabe 57? Ist es ein Fehler in PHP?
Ich glaube, dass viele Studenten solche Fragen hatten, weil es viele Leute gibt, die mir ähnliche Fragen stellen Fragen und noch mehr Unnötig zu erwähnen, dass Leute oft auf bugs.php.net gestellt werden...
Um diesen Grund zu verstehen, müssen wir zunächst die Darstellung von Gleitkommazahlen (IEEE 754) kennen:
Gleitkommazahlen in 64-Bit-Form. Beispielsweise wird die Länge (doppelte Genauigkeit) durch 1 Vorzeichenbit (E), 11 Exponentenbits (Q) und 52 Mantissenbits (M) (insgesamt) dargestellt von 64 Bits).
Vorzeichenbit: dargestellt durch das höchste Bit. Das Vorzeichen der Daten, 0 steht für eine positive Zahl und 1 für eine negative Zahl.
Exponentenbit: Stellt die Potenz der Daten zur Basis 2 dar, und der Exponent wird durch einen Offset-Code dargestellt.
Mantisse: Stellt die signifikanten Stellen nach dem Dezimalpunkt der Daten dar.
Die wichtigsten Punkte hier sind die Darstellung von Dezimalzahlen im Binärformat. Ich werde hier nicht näher darauf eingehen binäre Darstellung, 0,58 ist ein unendlicher Wert (die Zahlen unten lassen die implizite 1 weg). 7 ist im Grunde (52 bits): 0010001 111010111000010100011110101110000101000111101
And two Or binary, if calculated only through these 52 bits, they are:
Copy the code
Was 0,58 betrifft * Wir werden die spezifische Gleitkomma-Multiplikation von 100 nicht im Detail betrachten Arithmetik... 0,58 * 100 = 57,999999999
0.58 -> 0.57999999999999996 0.57 -> 0.56999999999999995
Dann kann man es natürlich intvalieren. Das sind 57…
Es ist ersichtlich, dass der Kernpunkt dieses Problems lautet: „Ihre scheinbar endliche Dezimalzahl ist in der Binärdarstellung des Computers tatsächlich unendlich“
Das obige ist der detaillierte Inhalt vonFragen zur PHP-Gleitkommagenauigkeit. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!