2012-05-29 7 views
10

Angenommen, t, a, b sind alle Doppel (IEEE Std 754) Variablen, und beide Werte von a, b sind NICHT NaN (aber Inf sein kann). Muss ich nach t = a - b unbedingt a == b + t haben?IEEE Std 754 Fließkommazahl: let t: = a - b, garantiert der Standard, dass a == b + t?

+0

Ich glaube, das Ergebnis eines Unterlaufs würde undefiniert sein, und so würde das eines Überlaufs im zweiten Ausdruck, also nein. Wenn jemand das bestätigen könnte, wäre es nett. – chris

+0

Ah, ich denke, diese Art bestätigt, dass der Überlauf auch für Gleitkommazahlen undefiniert ist: ' mit einem anderen arithmetischen Überlauf, wenn das Ergebnis nicht in den angegebenen Bereich passt, ist das Verhalten nicht definiert. – chris

+3

In einer C-Implementierung Gemäß IEEE 754 gibt es kein UB für Gleitkomma-Arithmetik. Alle Ergebnisse sind streng definiert. –

Antwort

25

Absolut nicht. Ein offensichtlicher Fall ist a=DBL_MAX, b=-DBL_MAX. Dann t=INFINITY, also b+t ist auch INFINITY.

Was überraschender ist, ist, dass es Fälle gibt, in denen dies ohne Überlauf geschieht. Im Grunde sind sie alle von der Form, in der a-b ungenau ist. Wenn beispielsweise a ist DBL_EPSILON/4 und b-1 ist, a-b 1 (Standardrundungsmodus angenommen wird), und ist dann 0. a-b+b

Der Grund I Dieses zweite Beispiel erwähnen ist, dass dies die kanonische Weise zwingen Rundung auf eine bestimmte Genauigkeit in der IEEE-Arithmetik. Wenn Sie beispielsweise eine Zahl im Bereich [0,1] haben und erzwingen möchten, dass sie auf 4 Bits genau gerundet wird, fügen Sie hinzu und subtrahieren Sie dann 0x1p49.

+1

Das zweite Beispiel ist großartig, da es weder Inf noch NaN ergibt. Danke vielmals. – updogliu

+1

Sie könnten die '0x1p49'-Konstante klären, das letzte Mal, als ich hexadezimale Ziffern von 0 bis F gesucht habe;) – MSalters

+8

@MSalters: "0x1p49" ist hexadezimales Gleitkomma, wie im C-Standard definiert. Das Format ist "0x" "p" , wobei eine hexadezimale Zahl ist, die optional eine Periode enthält, und eine Dezimalzahl ist, die optional ein Zeichen enthält. Die Basis für den Exponenten ist zwei, also ist 0x1p49 2 ** 49. 0x1p-4 wäre 1/16, und 0x1.23p8 wäre (1 + 2/16 + 3/256) * 2 ** 8 = 291. Hexadezimale Gleitkommazahlen bieten ein Format, das für Menschen und Compiler leicht zu konvertieren ist zu und von binären Fließkomma-Codierungen ohne Rundungsprobleme. –

1

Bei der ersten Operation konnten Bits vom unteren Ende des Ergebnisses verloren gehen. Eine Frage ist also, wird die zweite Operation genau diese Verluste reproduzieren? Ich habe das noch nicht ganz durchdacht.

Aber natürlich könnte die erste Operation zu +/- unendlich übergelaufen sein, was den zweiten Vergleich ungleich macht.

(Und natürlich, im allgemeinen Fall == für Gleitkommawerte verwendet, ist fast immer ein Fehler.)

+1

Nur durch ein Zählargument kann die zweite Operation nicht zurückbringen, was verloren gegangen ist. Wenn es könnte, würden Sie mehr Bits von Informationen in "t" speichern als die Anzahl von Bits in "t" ... –

+0

@R - Ja. Intuitiv weiß man, dass es nicht funktionieren wird, aufgrund dessen, was Sie sagen, aber Beispiele zu finden, ist besser "Beweis", als eine esoterische Regel anzustreben, egal wie gültig. –

-3

Sie sind nicht alles garantiert, wenn Floats mit. Wenn der Exponent für beide Zahlen unterschiedlich ist, kann das Ergebnis einer arithmetischen Operation möglicherweise nicht vollständig in einem Gleitkomma dargestellt werden.

diesen Code vor:

float a = 0.003f; 
float b = 10000000.0f; 
float t = a - b; 
float x = b + t; 

auf Visual Studio 2010 Rennen, erhalten Sie t==-10000000.0f und damit x==0.

Sie sollten niemals Gleichheit verwenden, wenn Sie Floats vergleichen. Vergleichen Sie stattdessen den absoluten Wert der Differenz zwischen beiden Werten und einen Epsilon-Wert, der klein genug für Ihre Präzisionsanforderungen ist.

Es wird noch seltsamer, da verschiedene Gleitkomma-Implementierungen unterschiedliche Ergebnisse für die gleiche Operation zurückgeben können.

+5

Ich mochte nie den Ratschlag "den absoluten Wert der Differenz vergleichen". Es ist möglich, Fehler zu vermeiden ([Was jeder Informatiker über Fließkomma-Arithmetik wissen sollte] (http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html) ist eine gute Sache Start) und man sollte darüber nachdenken, was man mit dem Vergleich erreichen will, bevor man blind auf irgendeine willkürliche Grenze umschaltet. –

+8

Es gibt viele Dinge, die bei Verwendung von IEEE-754-Schwimmern garantiert sind. Das gehört nicht dazu. –

+0

Es gibt viele Garantien bei der Verwendung von IEEE-Floats, und es gibt Zeiten, in denen der Vergleich auf Gleichheit nicht nur sinnvoll, sondern auch unerlässlich ist. Fließkomma-Mathematik ist definitiv schwierig, aber nicht zufällig oder bösartig. Hier ist ein Beispiel aus meinem Blog, in dem das Testen auf Fließkomma-Gleichheit kritisch ist: https://randomascii.wordpress.com/2014/01/27/theres-only-four-billion-floatsso-test-them-all/ –

Verwandte Themen