C # int wird im doppelten Genauigkeitsproblem "==" gespeichert

9
___ answer4290766 ___

Ja. 32-Bit-Ganzzahlen können genau als 64-Bit-Gleitkommazahlen dargestellt werden.

    
___ answer4290784 ___

Ich habe Visual Studio geöffnet und getestet.

Hier ist mein Code:

%Vor%

Das Ergebnis waren zwei Messageboxen, die "true" sagten.

Ich schätze, das kommt zu dem Schluss: Ja, Sie werden garantiert, dass es wahr sein wird.

EDIT: Habe meinen Test etwas verlängert. Der einzige Test, der falsch zurücklief, war der Test bei double.MaxValue, aber ich bezweifle, dass Sie diese großen Zahlen verwenden werden.

    
___ answer4290843 ___

Ja, Sie können eine (32-Bit-) Ganzzahl in a == b (64-Bit-Gleitkommazahl) ohne Präzisionsverlust speichern.

Sobald Sie jedoch Berechnungen mit Ihrem %code% durchführen, werden Sie sehr wahrscheinlich Rundungsfehler, d. h. Präzisionsverlust, einführen. Diese Fehler sind wahrscheinlich klein genug, sodass sie weggerundet werden, wenn Sie Ihren %code% -Wert wieder auf %code% setzen - aber der Fehler ist dort, also beachten Sie es.

Wie es gemacht wird: Siehe dieses Dokument ( IEEE Standard 754 Fließkommazahlen von Steve Hollasch für Details darüber, wie eine ganze Zahl als Gleitkommawert gespeichert werden kann.

Um (etwas ungenau) zusammenzufassen, besteht ein Fließkommawert aus drei Teilen: Ein Vorzeichenbit, ein "Bruch" -Teil (Mantisse genannt) und ein "Exponent" -Teil. Sie sind grob wie folgt zusammengesetzt:

Wert = -1 Vorzeichenbit × Bruch × 2 Exponent

Sie können den ganzzahligen Wert im "fraction" -Teil von %code% speichern (was 52 Bits breit ist, was mehr als breit genug für eine 32-Bit-Ganzzahl ist. Der "Exponent" -Teil kann einfach auf gesetzt werden 0, da es nicht benötigt wird.

    
___ tag123c ___ C # (sprich "Cis") ist eine objektorientierte Programmiersprache auf hohem Niveau, die für die Erstellung einer Vielzahl von Anwendungen entwickelt wurde, die auf dem .NET Framework (oder .NET Core) ausgeführt werden. C # ist einfach, leistungsfähig, typsicher und objektorientiert. ___ tag123double ___ Fließkommaformat mit doppelter Genauigkeit ist ein (meist) 64-Bit-Datentyp, der zum Speichern von Bruchzahlen verwendet wird. ___ tag123int ___ Ein Datentyp, der eine ganze Zahl darstellt. Eine ganze Zahl ist eine ganze Zahl, die negativ, positiv oder null sein kann. (d. h. ...- 2, -1, 0, 1, 2 ...) Verwenden Sie dieses Tag für Fragen zum Verwenden, Speichern oder Bearbeiten von Ganzzahlen. ___ tag123precision ___ Für Fragen zur numerischen Genauigkeit in der Programmierung. ___ answer4290922 ___
  

Ist sichergestellt, dass a == b wahr ist?

Ja. Dies liegt daran, dass Sie die gleiche Konvertierung zweimal durchführen und aufgrund ihres deterministischen Verhaltens die gleichen Werte erhalten, unabhängig von den Rundungsproblemen.

Wir können jedoch Ihre Frage verallgemeinern:

  

Können wir arithmetische Operationen an 32-Bit-Integer-Werten ausführen, die in %code% type ohne Genauigkeit loose codiert sind?

Die Antwort auf eine solche Frage lautet ja auch.

Eine kurze Begründung ist, dass Operationen auf Mantissen-Bits (siehe Ссылка ) genau sind, wenn es nur möglich ist und im Fall von 32-Bit-Integer-Werten ist es möglich.

Längere Geschichte kommt hier. Solange Ihr Integer-Wert in 52 Bits eines Fraktionsteils mit der Bezeichnung Mantisse passt (siehe Ссылка ), werden alle Berechnungen für ganzzahlige Werte mit double verhält sich vollständig OK.

Dies liegt daran, dass Ihre Zahl (zB 173, die %code% binary ist) als %code% dargestellt wird, was genau ist.

Alle Operationen auf Mantisse sind einfach, solange sie in die Mantisse passen. Rundungen auf Ganzzahlen treten auf, wenn das Ergebnis einer bestimmten Operation nicht in die Mantisse passt - z. Sie würden 40 Bits Mantisse mit 40 Bits Mantisse multiplizieren. Das Runden von Gleitkommaoperationen tritt zusätzlich auf, wenn Exponenten sehr unterschiedlich sind. In diesem Fall kann sogar eine einfache Additionsoperation die Präzision verlieren, weil Matinsas verschoben werden.

Zurück zu Ganzzahlen, die im Double-even-Division-Verfahren codiert sind, ist präzise, ​​solange das Ergebnis ein Integer-Wert ist. Also ist %code% auch garantiert wahr.

Das Problem beginnt, wenn Ihre Nummer keine Ganzzahl ist. Aber auch in diesem Fall werden Zahlen garantiert dargestellt, wenn sie eine Form von %code% und %code% in 52 Bits darstellen (zB %code% %code% %code% ). Operationen auf solchen Zahlen sind auch präzise, ​​da %code% für beide Operanden gleich sein kann, also gerade:

%Vor%

ist garantiert wahr.

Interessant ist, dass Sie Operationen mit 54-Bit-Ganzzahlen mit Vorzeichen sicher ausführen können. Dies liegt daran, dass Sie am Anfang ein zusätzliches Bit haben, dessen Bedeutung durch den Exponenten und ein zusätzliches Bit für ein Zeichen kodiert wird. Nun -2 ^ 53, was MIN_INT im Falle einer 54 Bit signierten Ganzzahl nicht zur Mantisse passen würde, aber der Exponent wird hier die Aufgabe übernehmen mit Mantisse voller Nullen.

    
___ qstnhdr ___ C # int wird im doppelten Genauigkeitsproblem "==" gespeichert ___
levanovd 27.11.2010, 08:31
quelle

4 Antworten

10

Ja. 32-Bit-Ganzzahlen können genau als 64-Bit-Gleitkommazahlen dargestellt werden.

    
Ian Henry 27.11.2010, 08:35
quelle
9
  

Ist sichergestellt, dass a == b wahr ist?

Ja. Dies liegt daran, dass Sie die gleiche Konvertierung zweimal durchführen und aufgrund ihres deterministischen Verhaltens die gleichen Werte erhalten, unabhängig von den Rundungsproblemen.

Wir können jedoch Ihre Frage verallgemeinern:

  

Können wir arithmetische Operationen an 32-Bit-Integer-Werten ausführen, die in double type ohne Genauigkeit loose codiert sind?

Die Antwort auf eine solche Frage lautet ja auch.

Eine kurze Begründung ist, dass Operationen auf Mantissen-Bits (siehe Ссылка ) genau sind, wenn es nur möglich ist und im Fall von 32-Bit-Integer-Werten ist es möglich.

Längere Geschichte kommt hier. Solange Ihr Integer-Wert in 52 Bits eines Fraktionsteils mit der Bezeichnung Mantisse passt (siehe Ссылка ), werden alle Berechnungen für ganzzahlige Werte mit double verhält sich vollständig OK.

Dies liegt daran, dass Ihre Zahl (zB 173, die 0000010101101b binary ist) als 1.010110100000b*2^7 dargestellt wird, was genau ist.

Alle Operationen auf Mantisse sind einfach, solange sie in die Mantisse passen. Rundungen auf Ganzzahlen treten auf, wenn das Ergebnis einer bestimmten Operation nicht in die Mantisse passt - z. Sie würden 40 Bits Mantisse mit 40 Bits Mantisse multiplizieren. Das Runden von Gleitkommaoperationen tritt zusätzlich auf, wenn Exponenten sehr unterschiedlich sind. In diesem Fall kann sogar eine einfache Additionsoperation die Präzision verlieren, weil Matinsas verschoben werden.

Zurück zu Ganzzahlen, die im Double-even-Division-Verfahren codiert sind, ist präzise, ​​solange das Ergebnis ein Integer-Wert ist. Also ist 4.0/2.0 == 8.0/4.0 auch garantiert wahr.

Das Problem beginnt, wenn Ihre Nummer keine Ganzzahl ist. Aber auch in diesem Fall werden Zahlen garantiert dargestellt, wenn sie eine Form von x/2^y und x in 52 Bits darstellen (zB 3/4 5/8 345/1024 ). Operationen auf solchen Zahlen sind auch präzise, ​​da y für beide Operanden gleich sein kann, also gerade:

%Vor%

ist garantiert wahr.

Interessant ist, dass Sie Operationen mit 54-Bit-Ganzzahlen mit Vorzeichen sicher ausführen können. Dies liegt daran, dass Sie am Anfang ein zusätzliches Bit haben, dessen Bedeutung durch den Exponenten und ein zusätzliches Bit für ein Zeichen kodiert wird. Nun -2 ^ 53, was MIN_INT im Falle einer 54 Bit signierten Ganzzahl nicht zur Mantisse passen würde, aber der Exponent wird hier die Aufgabe übernehmen mit Mantisse voller Nullen.

    
agsamek 27.11.2010 09:23
quelle
3

Ja, Sie können eine (32-Bit-) Ganzzahl in double (64-Bit-Gleitkommazahl) ohne Präzisionsverlust speichern.

Sobald Sie jedoch Berechnungen mit Ihrem double durchführen, werden Sie sehr wahrscheinlich Rundungsfehler, d. h. Präzisionsverlust, einführen. Diese Fehler sind wahrscheinlich klein genug, sodass sie weggerundet werden, wenn Sie Ihren double -Wert wieder auf int setzen - aber der Fehler ist dort, also beachten Sie es.

Wie es gemacht wird: Siehe dieses Dokument ( IEEE Standard 754 Fließkommazahlen von Steve Hollasch für Details darüber, wie eine ganze Zahl als Gleitkommawert gespeichert werden kann.

Um (etwas ungenau) zusammenzufassen, besteht ein Fließkommawert aus drei Teilen: Ein Vorzeichenbit, ein "Bruch" -Teil (Mantisse genannt) und ein "Exponent" -Teil. Sie sind grob wie folgt zusammengesetzt:

Wert = -1 Vorzeichenbit × Bruch × 2 Exponent

Sie können den ganzzahligen Wert im "fraction" -Teil von double speichern (was 52 Bits breit ist, was mehr als breit genug für eine 32-Bit-Ganzzahl ist. Der "Exponent" -Teil kann einfach auf gesetzt werden 0, da es nicht benötigt wird.

    
stakx 27.11.2010 09:02
quelle
-1

Ich habe Visual Studio geöffnet und getestet.

Hier ist mein Code:

%Vor%

Das Ergebnis waren zwei Messageboxen, die "true" sagten.

Ich schätze, das kommt zu dem Schluss: Ja, Sie werden garantiert, dass es wahr sein wird.

EDIT: Habe meinen Test etwas verlängert. Der einzige Test, der falsch zurücklief, war der Test bei double.MaxValue, aber ich bezweifle, dass Sie diese großen Zahlen verwenden werden.

    
Jan Sverre 27.11.2010 08:39
quelle

Tags und Links