Vorwort: Wenn es bei der Arbeit um Addition, Subtraktion, Multiplikation und Division mit Dezimalstellen geht, werden sie darüber nachdenken, BigDecimal zu verwenden, um das Problem zu lösen, aber viele Leute sind verwirrt darüber, warum Double oder Float verlieren an Präzision. Und wie löst man BigDecimal? Lassen Sie uns ohne weitere Umschweife beginnen.
1. Was sind Gleitkommazahlen?
Gleitkommazahlen sind ein Datentyp, der von Computern zur Darstellung von Dezimalzahlen in wissenschaftlicher Notation verwendet wird. In Java ist double eine 64-Bit-Gleitkommazahl mit doppelter Genauigkeit und der Standardwert ist 0,0d. float ist eine 32-Bit-Gleitkommazahl mit einfacher Genauigkeit, der Standardwert ist 0,0f
wird im Speicher gespeichert
float Vorzeichenbit (1 Bit) Exponent (8 Bit) Mantisse (23 Bit)
Doppeltes Vorzeichenbit (1 Bit) Exponent (11 Bit) Mantisse (52 Bit)
Der Exponent von Float im Speicher beträgt 8 Bit, da der Exponent Der Code speichert tatsächlich den Frameshift des Exponenten. Unter der Annahme, dass der wahre Wert des Exponenten e und der Bestellcode E ist, dann ist E=e+(2^n-1 -1). Unter diesen ist 2^n-1 -1 der durch den IEEE754-Standard angegebene exponentielle Offset. Nach dieser Formel können wir 2^8 -1=127 erhalten. Daher beträgt der Exponentenbereich von float -128 +127 und der Exponentenbereich von double -1024 +1023. Der negative Exponent bestimmt die Zahl ungleich Null mit dem kleinsten Absolutwert, den eine Gleitkommazahl ausdrücken kann, und der positive Exponent bestimmt die Zahl mit dem größten Absolutwert, den eine Gleitkommazahl ausdrücken kann Wertebereich einer Gleitkommazahl.
Der Bereich von float beträgt -2^128 ~ +2^127, was -3,40E+38 ~ +3,40E+38 entspricht; der Bereich von
double beträgt -2^1024 ~ + 2^1023, also -1,79E+308 ~ +1,79E+308
2. Einstieg in die wissenschaftliche Notation
Lassen Sie uns zunächst über die wissenschaftliche Notation sprechen Eine vereinfachte Zählmethode, die verwendet wird, um eine sehr große oder kleine Zahl mit einer großen Anzahl von Ziffern näherungsweise darzustellen. Bei Werten mit einer kleinen Anzahl von Ziffern hat die wissenschaftliche Notation keinen Vorteil, bei Werten mit einer großen Anzahl von Ziffern jedoch. Die wissenschaftliche Notation ist besser. Beispiel: Die Lichtgeschwindigkeit beträgt 300000000 Meter/Sekunde und die Weltbevölkerung beträgt etwa 6100000000. Große Zahlen wie die Lichtgeschwindigkeit und die Weltbevölkerung sind sehr schwer zu lesen und zu schreiben, daher kann die Lichtgeschwindigkeit als 3*10^8 und die Weltbevölkerung als 6,1*10^9 geschrieben werden. Daher verwendet der Rechner die wissenschaftliche Schreibweise, um anzugeben, dass die Lichtgeschwindigkeit 3E8 beträgt und die Weltbevölkerung etwa 6,1E9 beträgt.
Als wir Kinder waren, spielten wir mit Taschenrechnern und addierten oder subtrahierten wie verrückt. Am Ende zeigte der Taschenrechner das folgende Bild an. Dies ist das in wissenschaftlicher Notation angezeigte Ergebnis
Der tatsächliche Wert im Bild ist -4,86*10^11=-486000000000. Die wissenschaftliche Dezimalschreibweise erfordert, dass der ganzzahlige Teil der signifikanten Ziffer innerhalb des Intervalls [1, 9] liegen muss.
3. Lernen Sie die Präzision der Verzerrung kennen
Die Computerverarbeitung von Daten umfasst die Datenkonvertierung und verschiedene komplexe Vorgänge, wie z. B. die Umrechnung verschiedener Einheiten und verschiedener Basen B. binäre Dezimalkonvertierung usw., viele Divisionsoperationen können nicht geteilt werden, z. B. 10 ÷ 3 = 3,3333 ... unendlich, und die Genauigkeit ist begrenzt. 3,3333333 x 3 ist nicht gleich 10, die nach komplexer Verarbeitung erhaltene Dezimalzahl Die Daten ist nicht präzise und je höher die Genauigkeit, desto genauer. Die Genauigkeit von Float und Double wird durch die Anzahl der Stellen in der Mantisse bestimmt. Da der ganzzahlige Teil immer eine implizite „1“ ist, kann er die Genauigkeit nicht beeinflussen. float: 2^23 = 8388608, insgesamt sieben Ziffern. Da die Ziffer ganz links weggelassen wird, bedeutet dies, dass sie bis zu 8 Ziffern darstellen kann: 28388608 = 16777216. Es gibt 8 signifikante Ziffern, aber es ist absolut garantiert, dass es sich um 7 Ziffern handelt, d ist 16~17 Bit.
Wenn es einen bestimmten Wert erreicht, beginnt es automatisch mit der wissenschaftlichen Notation und behält signifikante Zahlen mit relevanter Genauigkeit bei, sodass das Ergebnis eine ungefähre Zahl und der Exponent eine ganze Zahl ist. Im Dezimalsystem können einige Dezimalzahlen nicht vollständig binär ausgedrückt werden. Daher kann es nur durch begrenzte Bits dargestellt werden, sodass es bei der Speicherung zu Fehlern kommen kann. Um Dezimalzahlen in Binärzahlen umzuwandeln, verwenden Sie zur Berechnung die Multiplikation mit 2. Nachdem Sie den ganzzahligen Teil entfernt haben, multiplizieren Sie die verbleibenden Dezimalzahlen weiter mit 2, bis alle Dezimalteile 0 sind.
Wenn Sie auf
stoßen, ist die Ausgabe 0,1999999999999998
doppelter Typ 0,3-0,1. Sie müssen 0,3 in der Operation
0,3 * 2 = 0,6 => .01 (. 2) Nimm 1 und belasse 0,2
0,2 * 2 = 0,4 => .010 (.4) Nimm 0 und belasse 0,4
0,4 * 2 = 0,8 => .0100 (.8) Nimm 0 und belasse 0,8
0,8 * 2 = 1,6 => .01001 (.6) nimmt 1 und belässt 0,6
.............
3. Zusammenfassung
Nach dem Lesen des oben Gesagten ist wahrscheinlich klar, warum Gleitkommazahlen Probleme mit der Genauigkeit haben. Einfach ausgedrückt sind die Typen „float“ und „double“ hauptsächlich für wissenschaftliche Berechnungen und technische Berechnungen konzipiert. Sie führen binäre Gleitkommaoperationen durch, die sorgfältig entwickelt wurden, um genauere und schnellere Nahsummenberechnungen über einen weiten Wertebereich zu ermöglichen. Sie liefern jedoch keine völlig genauen Ergebnisse und sollten nicht für präzise Ergebnisse verwendet werden. Gleitkommazahlen, die eine bestimmte Größe erreichen, verwenden automatisch die wissenschaftliche Notation. Eine solche Darstellung ist nur eine Näherung der reellen Zahl, aber nicht gleich der reellen Zahl. Bei der Umwandlung von Dezimalzahlen in Binärzahlen kann es auch zu Endlosschleifen oder zu Überschreitungen der Länge der Gleitkomma-Mantisse kommen.
4. Wie verwenden wir BigDecimal, um es zu lösen?
Sehen Sie sich die beiden Ausgaben unten an
Ausgabeergebnis:
0,299999999999999988897769753748434595763683319091796875
Auf dem Bild Das Code-Einschränkungs-Plug-In von Alibaba hat eine Warnung markiert und mich aufgefordert, die Konstruktormethode von String-Parametern zu verwenden, um BigDecimal zu erstellen. Da double nicht genau als 0,3 (jede Binärdatei endlicher Länge) dargestellt werden kann, ist der vom Konstruktor übergebene Wert nicht genau gleich 0,3. Wenn Sie BigDecimal verwenden, müssen Sie zum Erstellen die Konstruktormethode der String-Parameter verwenden. Apropos: Gibt es neugierige Babys, die Fragen haben, was das Prinzip von BigDecimal ist? Warum gibt es kein Problem damit? Tatsächlich ist das Prinzip sehr einfach. BigDecimal ist unveränderlich und kann zur Darstellung vorzeichenbehafteter Dezimalzahlen beliebiger Genauigkeit verwendet werden. Das Problem mit double besteht darin, dass die Konvertierung des Dezimalpunkts in den Binärwert an Präzision verliert. Während der Verarbeitung erweitert BigDecimal die Dezimalzahl um das N-fache, sodass sie auf Ganzzahlen berechnet werden kann und die entsprechenden Präzisionsinformationen beibehält. Wie BigDecimal gespeichert wird, können Sie im Quellcode nachlesen. Weitere technische Artikel zu häufig gestellten Fragen finden Sie in der SpalteDas obige ist der detaillierte Inhalt vonWarum verlieren doppelte Gleitkommaoperationen an Präzision?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!