2010-12-03 2 views
4

Ich möchte überprüfen, ob eine IEEE754 32-Bit-Nummer den Wert von genau 0.0f hat (es wird gelegentlich darauf festgelegt.) Akkumulationsfehler werden Null sein, da die Daten häufig aktualisiert werden von einem Sensor. Mein Prozessor hat keine Hardware-FPU, daher werden die Operationen in einer relativ schnellen Software-Bibliothek ausgeführt. Es gibt jedoch immer noch Hunderte von Zyklen für Dinge wie Addieren, Subtrahieren und Vergleichen.Vergleichen Sie eine Fließkommazahl mit Null

Also habe ich mich gefragt, warum mein Compiler dies tut:

240:     if(p_viewer->roll != 0.0f) 
03FBC B81160  mul.uu w2,#0,w2 
03FBE 900A2E  mov.w [w14+20],w4 
03FC0 900064  mov.w [w4+12],w0 
03FC2 9000F4  mov.w [w4+14],w1 
03FC4 07E91F  rcall __nesf2 
03FC6 E00000  cp0.w w0 
03FC8 320054  bra z, 0x004072 

__nesf2 vergleicht scheinbar zwei Gleitkommazahlen. Warum vergleicht man nicht einfach einen Vergleich mit 0.0f in ganzzahliger Form, also 0x00000000? Gibt es einen Grund, warum es das nicht tut oder ist es nur eine verpasste Optimierungsmöglichkeit?

Mein Compiler ist MPLAB C30, eine Version von GCC v3.23.

Antwort

7

Weil -0.0f auch gleich 0.0f entspricht, wie vom IEEE-754-Standard gefordert.

Sie können den Aufruf durch einen Vergleich mit den Ganzzahldarstellungen von -0 (0x80000000) und +0 ersetzen, wenn dies ein schwerwiegendes Leistungsproblem darstellt. (Oder noch besser: Maskiere das Vorzeichen und vergleiche es mit 0.0f).

+1

Ich habe mich gefragt, warum die Compiler dies nicht getan, wäre es wahrscheinlich nur 10 Zyklen maximal sein, während der __nesf2 Funktion dauert etwa 100 Zyklen. –

+1

Ohne das Signalisierungs-NaN-Problem ist dies nur eine verpasste Optimierung. Füge einen Fehler ein. –

+0

Und unter Berücksichtigung des Alters des Compilers (gcc 3.2.3?) Ist es wahrscheinlich, dass (a) es viele verpasste Optimierungen gibt, und (b) niemand daran interessiert ist, es zu beheben. –

1

Wenn es sich um eine IEEE-Gleitkomma-Implementierung handelt, müssen die Signal-NANs berücksichtigt werden.

Das interessiert Sie vielleicht nicht, aber der Compiler weiß das nicht.

+0

Ja, aber ist das egal? NaN würde niemals mit Nicht-NaN gleichgesetzt werden. –

+0

@Thomas O: eine Signalisierung NaN könnte eine Falle verursachen, während der Ganzzahl-Vergleich nicht würde. Software-FP-Implementierungen unterstützen jedoch fast nie die Signalisierung von NaNs, daher ist dies unwahrscheinlich. –

+0

@Stephen Canon, ich glaube nicht, dass meine Signale NaNs haben. Sie können durch Null teilen, aber Sie erhalten nur NaN. Nichts anderes passiert. –

1

Es ist eine verpasste Optimierungsmöglichkeit. 0.f ist ein Sonderfall, da ein Vergleich mit -0.f und 0f durchgeführt werden muss. Aber es wäre immer noch schneller zu vergleichen als ints.

Warum ist es nicht optimiert? Ich würde wetten, dass es ein Integrationsproblem ist. Solche Sachen fallen normalerweise zwischen Stühle. Die Leute, die die Aufgabe haben, das Plattform-SDK zusammenzustellen, wählen einen Compiler (gcc), eine Software-Float-Bibliothek, und schaffen es, sie so gut wie möglich zusammenzukleben. Dies funktioniert im allgemeinen Fall OK, und es gibt wenig Motivation für Verbesserungen, da Software-Floats im Allgemeinen sowieso sehr langsam sind. Das Schlimmste ist nicht der Vergleich, sondern all die anderen Sachen.

Einfach gesagt, wenn Sie Software schwebt, gibt es keinen Sinn, sie zu verwenden, wenn Sie Leistung benötigen. Verwenden Sie dafür einen festen Punkt.

+0

'0.f' ist ein Sonderfall? * Irgendwelche * Gleitkommawerte können Bit für Bit verglichen werden, solange Sie wissen, dass einer von ihnen nicht NaN ist (zum Beispiel wenn einer von ihnen eine Literalkonstante ist). Eigentlich ist Null das Schlimmste, weil man die positive und negative Null überprüfen muss. Für jeden anderen Wert genügt ein einziger Vergleich. –

+0

Ja, das ist, was ich mit 0.f als Sonderfall meinte ... –

0

Um zu überprüfen, gegen 0.0f Sie IEEE Sachen nicht benötigen, wie:

int isFloatNull(float f) 
{ 
    static float i; 
    return !memcmp(&i,&f,sizeof i); 
} 
+0

Nicht zu viel Gewinn dort - nur einen Funktionsaufruf durch einen anderen ersetzen ... –

+0

@kotlinski Wenn es schneller ist, dann ist es besser, es spielt keine Rolle wenn es Funktionsaufrufe ersetzt. –

+0

Es wird natürlich das falsche Ergebnis für negative Nullen geben, also ist das ziemlich nutzlos. – gnasher729