Warum sehe ich eine doppelte Variable auf einen Wert wie 21,4 als 21,399999618530273 initialisiert?

StackOverflow https://stackoverflow.com/questions/177506

  •  05-07-2019
  •  | 
  •  

Frage

double r = 11.631;
double theta = 21.4;

Im Debugger werden diese dargestellt als 11.631000000000000 und 21.399999618530273.

Wie kann ich das vermeiden?

War es hilfreich?

Lösung

Andere Tipps

Ich mochte Joel Erklärung , die mit einem ähnlichen binären Fließ beschäftigt Punkt Präzision Ausgabe in Excel 2007:

  

Sehen Sie, wie es eine Menge von 0110 0110 0110 gibt es am Ende? Das liegt daran, 0,1 hat keine genaue Darstellung in binär ... es ist eine sich wiederholende binäre Zahl. Es ist ein bisschen wie, wie 1/3 keine Darstellung in dezimal hat. 1/3 ist 0,33333333 und Sie müssen halten 3 schreibt für immer. Wenn Sie die Geduld verlieren, erhalten Sie etwas ungenauer.

     

So können Sie sich vorstellen, wie, in dezimal, wenn man versucht, 3 zu tun * 03.01, und Sie haben keine Zeit, 3s zu schreiben immer, wäre das Ergebnis, das Sie bekommen würde 0,99999999, nicht mehr als 1, und die Leute würden wütend mit Ihnen für falsch zu sein.

Wenn Sie einen Wert wie:

double theta = 21.4;

Und Sie wollen tun:

if (theta == 21.4)
{
}

Sie haben ein bisschen klug sein, müssen Sie, wenn der Wert von Theta überprüfen ist, wirklich die Nähe von 21,4, aber nicht unbedingt, dass Wert.

if (fabs(theta - 21.4) <= 1e-6)
{
}

Dies ist zum Teil plattformspezifisch - und wir wissen nicht, welche Plattform Sie verwenden

.

Es ist auch teilweise ein Fall von zu wissen, was Sie eigentlich will zu sehen. Der Debugger zeigt Ihnen - zu einem gewissen Grad jedenfalls - den genauen Wert in der Variable gespeichert. In meinem Artikel über binären Gleitkommazahlen in .NET , gibt es eine C # Klasse , die Ihnen die absolut sehen können genau Zahl im Doppel gespeichert. Die Online-Version ist zur Zeit nicht arbeiten -. Ich werde versuchen, ein auf einer anderen Website zu setzen

Da der Debugger den „tatsächlichen“ Wert sieht, es habe ein Urteil Anruf über das, was angezeigt werden - es Ihnen den Wert auf wenige Dezimalstellen gerundet zeigen kann, oder einen genaueren Wert. Einige Debugger machen einen besseren Job als andere Entwickler der Köpfe zu lesen, aber es ist ein grundsätzliches Problem mit binären Gleitkommazahlen.

Mit dem Festpunkt decimal Typ, wenn Sie Stabilität an den Grenzen der Präzision wollen. Es gibt Gemeinkosten, und Sie müssen explizit werfen, wenn Sie Gleitkomma konvertieren möchten. Wenn Sie Floating-Point-konvertiere werden Sie die Instabilitäten wieder einführen, die Sie zu stören scheinen.

Alternativ können Sie über ihn bekommen und lernen, arbeiten mit der begrenzten Genauigkeit der Gleitpunktarithmetik. Zum Beispiel können Sie Runden verwenden, um Werte zu machen konvergieren, oder Sie können epsilon Vergleiche verwenden, um eine Toleranz zu beschreiben. „Epsilon“ ist eine Konstante, die Sie einrichten, die eine Toleranz definiert. Zum Beispiel können wählen Sie zwei Werte zu betrachten, als gleich, wenn sie innerhalb 0,0001 voneinander sind.

Es kommt zu mir, dass Sie Betreiber Überlastung verwenden könnte epsilon Vergleiche transparent zu machen. Das wäre sehr cool.


Für Mantisse-Exponenten Darstellungen EPSILON muss berechnet werden innerhalb der darstellbaren Präzision zu bleiben. Für eine Reihe N, Epsilon = N / 10E + 14

System.Double.Epsilon ist der kleinste darstellbare positive Wert für den Double Typen. Es ist zu klein für unsere Zwecke. Lesen Sie Microsoft Rat auf Gleichheit zu testen

Ich habe über diese kommen vor ( auf mein Blog ) - ich denke, die Überraschung zu sein scheint, dass die ‚irrational‘ Zahlen unterschiedlich sind

.

Mit dem ‚irrational‘ hier ich beziehe ich nur auf die Tatsache, dass sie nicht genau in diesem Format dargestellt werden. Real irrationale Zahlen (wie π - pi). Nicht genau überhaupt dargestellt wird

Die meisten Menschen sind mit 1/3 nicht in dezimal arbeiten: ,3333333333333 ...

Das Seltsame ist, dass 1.1 nicht in Schwimmern nicht funktioniert. Die Menschen erwarten Dezimalwerte wegen in Gleitkommazahlen arbeiten, wie sie an sie denken:

  

1.1 ist 11 x 10 ^ -1

Wenn tatsächlich sind sie in der Basis-2

  

1.1 ist 154811237190861 x 2 ^ -47

Sie können es nicht vermeiden, müssen Sie nur auf die Tatsache gewöhnen, dass einige Schwimmer ‚irrational‘, auf die gleiche Art und Weise sind, dass ein Drittel ist.

Eine Möglichkeit, dies vermeiden kann, ist eine Bibliothek zu verwenden, die zur Darstellung von Dezimalzahlen eine alternative Methode verwendet, wie

Es scheint mir, dass 21,399999618530273 ist die single precision (float) Darstellung von 21,4. Sieht aus wie die Debugger Gießen von Double Down irgendwo zu schwimmen.

Wenn Sie Java verwenden und Genauigkeit benötigen, verwenden BigDecimal Klasse für Punkt Berechnungen schweben. Es ist langsamer, aber sicherer.

Sie kann dies vermeiden, wie Sie mit festen Menge von Bytes Gleitkommazahlen verwenden. Es gibt einfach keinen Isomorphismus möglich zwischen reellen Zahlen und ihrer begrenzten Notation.

Aber die meiste Zeit kann man es einfach ignorieren. 21,4 == 21,4 würde immer noch wahr sein, weil es immer noch die gleichen Zahlen mit dem gleichen Fehler. Aber 21.4f == 21.4 kann nicht wahr sein, da der Fehler für Schwimmer und Doppel unterschiedlich ist.

Wenn Sie Präzision fixieren müssen, sollten Sie vielleicht Festpunktzahl versuchen. Oder sogar ganze Zahlen. Ich zum Beispiel verwenden oft int (1000 * x) für das Debuggen Pager übergeben.

Wenn es Sie stört, können Sie die Art und Weise anpassen einige Werte während Debug angezeigt werden. Verwenden Sie es mit Sorgfalt: -)

Verbesserung des Debugging mit dem Debugger Anzeigeattribut

Siehe

Allgemeinen Dezimalarithmetik

Beachten Sie auch, wenn Schwimmer zu vergleichen, finden Sie unter diese Antwort für weitere Informationen.

Nach dem javadoc

"Wenn mindestens einer der Operanden auf einen numerischen Operator vom Typ double ist, dann ist die
    Betrieb ausgeführt wird unter Verwendung von 64-Bit-Fließkommaarithmetik, und das Ergebnis der
    numerische Operator ist ein Wert vom Typ double. Wenn der andere Operand keine doppelt so hoch ist, ist es
    zunächst aufgeweitet (§5.1.5) doppelt eingeben, indem numerische Förderung (§5.6). "

ist die Quelle

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top