Ich bin besorgt über die folgenden Fälle
%Vor%Laut Wikipedia IEEE 754-2008 sagt man zu min und max
Die Min- und Max-Operationen sind definiert, lassen aber Spielraum für den Fall, dass die Eingänge den gleichen Wert haben, sich aber in der Darstellung unterscheiden. Insbesondere:
min (+ 0, -0) oder min (-0, + 0) muss etwas mit einem Wert von Null ergeben, kann aber immer das erste Argument zurückgeben.
Ich habe einige Tests durchgeführt, um fmin
, fmax
, min und max wie unten definiert
und _mm_min_ps
und _mm_max_ps
, die die Anweisung SSE minps
und maxps
aufrufen.
Hier sind die Ergebnisse (der Code, mit dem ich das getestet habe, ist unten veröffentlicht)
%Vor% Wie Sie sehen können, gibt jeder Fall unterschiedliche Ergebnisse zurück. Meine Hauptfrage lautet also: Was sagen die C- und C ++ - Standardbibliotheken? Muss fmin(-0.0,0.0)
gleich -0.0
und fmax(-0.0,0.0)
müssen gleich 0.0
sein oder dürfen verschiedene Implementierungen definieren anders? Wenn die Implementierung definiert ist, bedeutet dies, dass zur Sicherstellung, dass der Code mit verschiedenen Implementierungen der C-Standardbibliothek (z. B. von verschiedenen Compilern) kompatibel ist, überprüft werden muss, wie sie min und max implementieren?
Was ist mit minmag(-x,x)
und maxmag(-x,x)
? Diese sind beide in IEEE 754-2008 definiert. Sind diese Implementierungen zumindest in IEEE 754-2008 definiert? Ich folge aus Wikepdias Kommentar zu min und max, dass diese Implementierungen definiert sind. Die C-Standardbibliothek definiert diese Funktionen jedoch nicht, soweit ich weiß. In OpenCL sind diese Funktionen definiert als
maxmag Gibt x zurück, wenn | x | & gt; | y |, oder y wenn | y | & gt; | x |, sonst fmax (x, y).
minmag Gibt x zurück, wenn | x | & lt; | y |, oder y wenn | y | & lt; | x |, sonst fmin (x, y).
Der x86-Befehlssatz enthält keine Anweisungen für minmag und maxmag, daher musste diese implementieren . Aber in meinem Fall brauche ich Leistung und eine Verzweigung für den Fall, wenn die Größen gleich sind, ist nicht effizient.
Der Itaninum-Befehlssatz hat minmag- und maxmag-Anweisungen ( famin
und famax
) und in diesem Fall gibt er, soweit ich das beurteilen kann (aus dem Lesen), das zweite Argument zurück. Das scheint nicht der Fall zu sein, was minps
und maxps
tun. Es ist seltsam, dass _mm_min_ps(-0.0,0.0) = 0.0
und _mm_max_ps(-0.0,0.0) = -0.0
. Ich hätte erwartet, dass sie entweder das erste Argument in beiden Fällen oder das zweite Argument zurückgeben würden. Warum sind die Anweisungen minps
und maxps
auf diese Weise definiert?
Bearbeiten:
In Bezug auf C ++ habe ich std::min(-0.0,0.0)
und std::max(-0.0,0.0)
getestet und beide geben -0.0
zurück. Dies zeigt, dass std::min
nicht mit fmin
übereinstimmt und std::max
nicht mit fmax
übereinstimmt.
Warum lesen Sie nicht selbst den Standard ? Der Wikipedia-Artikel für IEEE enthält Links zum Standard
Hinweis: Das C Standarddokument ist nicht frei verfügbar. Aber der endgültige Entwurf ist (das ist, was ich verlinkt habe, suche nach der PDF-Version). Allerdings habe ich nicht das letzte Dokument hier zitiert und AFAIK dort hatte meist einige Tippfehler korrigiert; Nichts hat sich geändert. IEEE ist jedoch kostenlos verfügbar.
Beachten Sie, dass ein Compiler sich nicht an die Standards halten muss (einige eingebettete Compiler / Versionen zum Beispiel implementieren keine IEEE-konformen Gleitkommawerte, sind aber immer noch C-konform - lesen Sie einfach den Standard für Details). Siehe die Compiler-Dokumentation, um die Kompatibilität zu sehen. MS-VC zum Beispiel ist nicht einmal kompatibel mit C99 (und wird es nie tun), während gcc und clang / llvm in den aktuellen Versionen (meist gcc seit 4.9.2, in Teilen seit 4.7) (meistens) kompatibel sind.
Wenn Sie MS-VC verwenden, überprüfen Sie im Allgemeinen, ob tatsächlich alle Standardfunktionen unterstützt. Es ist tatsächlich nicht vollständig kompatibel mit dem aktuellen Standard, noch C99.
Das grundlegende Problem in diesem Fall ist die eigentliche zugrundeliegende Mathematik, wobei Repräsentationsprobleme ignoriert werden. Es gibt mehrere Implikationen in Ihrer Frage, die ich für falsch halte. -0,0 & lt; 0.0 ist falsch. -0.0 ist eine negative Zahl ist falsch. 0.0 ist eine positive Zahl ist falsch. In der Tat gibt es keine -0.0, obwohl es eine IEEE 754-Darstellung von Null mit einem gesetzten Vorzeichen gibt.
Außerdem ist das Verhalten von Min / Max-Funktionen nur ein kleiner Teil legaler Fließkommaoperationen, die Nullen mit unterschiedlichen Vorzeichen ergeben können. Da Fließkommaeinheiten für Ausdrücke wie -7 bis -7 frei (-) 0.0 sein können, müßten Sie auch herausfinden, was damit zu tun ist. Ich möchte auch darauf hinweisen, dass | 0.0 | könnte tatsächlich 0.0 mit dem gesetzten Vorzeichenbit zurückgeben, da -0.0 ein Absolutwert von 0.0 ist. Was die Mathematik betrifft, so ist 0.0 -0.0. Sie sind das Gleiche.
Die einzige Möglichkeit, mit einem gesetzten Vorzeichenbit auf 0.0 zu testen, besteht darin, mathematische Ausdrücke zu verwerfen und stattdessen die binäre Darstellung solcher Werte zu untersuchen. Aber was soll das? Es gibt nur einen legitimen Fall, an den ich denken kann: die Erzeugung von Binärdaten von zwei verschiedenen Maschinen, die Bit für Bit identisch sein müssen. In diesem Fall müssen Sie sich auch um die Signalisierung und leise NaN-Werte kümmern, da es sehr viel mehr Aliase dieser Werte gibt (10 ^ 22-1 SNaNs und 10 ^ 22 QNaNs für Gleitkommazahlen einfacher Genauigkeit und etwa 10 ^ 51 Werte von jedem für doppelte Genauigkeit).
In solchen Situationen, in denen die binäre Darstellung kritisch ist (absolut NICHT für mathematische Berechnungen), müssen Sie Code schreiben, um alle Gleitkommazahlen zu schreiben (Nullen, stille NaNs und NaNs) ).
Für jeden Berechnungszweck ist es nutzlos, sich darüber Gedanken zu machen, ob das Vorzeichenbit gesetzt oder gelöscht ist, wenn der Wert Null ist.
Tags und Links c c++ sse floating-point ieee-754