Erlaubt der C ++ - Standard dieses Fließkomma-Verhalten?

8

Im folgenden Code:

%Vor%

Unter Verwendung von v4.9.3 g++ -std=c++14 targeting 32-bit Windows werde ich ausgegeben:

%Vor%

Sollen diese Werte unterschiedlich sein?

Ich habe erwartet, dass dies auch dann der Fall sein sollte, wenn der Compiler eine höhere interne Genauigkeit als double für die Berechnung von xi * xd verwendet. Der Genauigkeitsverlust bei der Fließkomma-Konvertierung ist implementierungsdefiniert , und auch die Genauigkeit dieser Berechnung ist implementierungsdefiniert - [c.limits] / 3 besagt, dass FLT_EVAL_METHOD sollte aus C99 importiert werden. IOW Ich habe erwartet, dass es nicht erlaubt sein sollte, eine andere Genauigkeit für xi * xd in einer Zeile zu verwenden als in einer anderen Zeile.

Hinweis: Dies ist absichtlich eine C ++ - Frage und keine C-Frage - ich glaube, dass die beiden Sprachen in diesem Bereich unterschiedliche Regeln haben.

    
M.M 21.12.2015, 05:07
quelle

2 Antworten

3
  

selbst wenn der Compiler eine höhere interne Genauigkeit als doppelt für die Berechnung von xi * xd verwendet, sollte es dies konsequent tun

Ob erforderlich oder nicht (siehe unten), dies ist eindeutig nicht der Fall: Stackoverflow ist übersät mit Fragen von Leuten, die ähnlich scheinende Berechnungen gesehen haben, die sich aus keinem Grund innerhalb des gleichen Programms geändert haben .

Der C ++ Standardentwurf n3690 sagt (Hervorhebung von mir):

  

Die Werte der Gleitkommaoperanden und die Ergebnisse der Gleitkommaausdrücke können mit einer größeren Genauigkeit und einem größeren Bereich dargestellt werden als vom Typ gefordert. die Typen werden dabei nicht geändert.62

     

62) Die Darsteller und Zuweisungsoperatoren müssen immer noch ihre spezifischen Konvertierungen durchführen, wie in 5.4, 5.2.9 und 5.17 beschrieben.

Also - in Übereinstimmung mit dem Kommentar von MM und im Gegensatz zu meiner früheren Bearbeitung - ist es die Version mit der (double) Besetzung, die muss auf 64-bit double gerundet werden - was offensichtlich ist passiert mit & gt; = 1180000000 in dem in der Frage dokumentierten Lauf - vor dem Abstumpfen auf Integer. Der allgemeinere Fall sans 62) lässt dem Compiler die Freiheit, im anderen Fall früh nicht zu runden.

  

[c.limits] / 3 besagt, dass FLT_EVAL_METHOD aus C99 importiert werden sollte. IOW Ich erwartete, dass es nicht erlaubt sein sollte, eine andere Genauigkeit für xi * xd in einer Zeile zu verwenden als in einer anderen Zeile.

Überprüfen Sie die cppreference-Seite :

  

Unabhängig von dem Wert von FLT_EVAL_METHOD kann jeder Gleitkommaausdruck zusammengezogen werden, dh so berechnet werden, als ob alle Zwischenergebnisse einen unendlichen Bereich und eine unendliche Genauigkeit aufweisen (es sei denn, #pragma STDC FP_CONTRACT ist ausgeschaltet)

Wie tmyklebu sagt, fährt er fort:

  

Cast und Assignment streichen jeden irrelevanten Bereich und jegliche Präzision weg: Dies modelliert die Aktion des Speicherns eines Werts von einem FPU-Register mit erweiterter Genauigkeit in einen Speicherbereich mit Standardgröße.

Letzteres stimmt mit dem "62)" Teil des Standards überein.

M. M. Kommentare:

  

STDC FP_CONTRACT scheint nicht im C ++ Standard zu erscheinen und es ist mir auch nicht klar, in welchem ​​Ausmaß das C99-Verhalten "importiert" wird

Erscheint nicht in dem Entwurf, den ich angeschaut habe. Dies deutet darauf hin, dass C ++ seine Verfügbarkeit nicht garantiert, so dass der oben erwähnte Standard von "jeder Gleitkommaausdruck kann kontrahiert werden" , aber wir wissen pro M.M. Kommentare und die Standard- und cppreference-Anführungszeichen oberhalb der (double) -Cast sind eine Ausnahme, die das Runden auf 64 Bits erzwingt.

Der oben erwähnte C ++ Standardentwurf sagt von <cfloat> :

  

Der Inhalt entspricht dem Header der Standard-C-Bibliothek.   Siehe auch: ISO C 7.1.5, 5.2.4.2.2, 5.2.4.2.1.

Wenn eine dieser C-Standards STDC FP_CONTRACT erfordert, besteht eine größere Chance, dass sie für die Verwendung von C ++ - Programmen portierbar ist, aber ich habe Implementierungen nicht nach Unterstützung durchgesehen.

    
Tony Delroy 21.12.2015 05:19
quelle
2

Abhängig von FLT_EVAL_METHOD kann xi * xd mit höherer Genauigkeit als doppelt berechnet werden. Wenn xi so groß ist, dass es nicht genau in double dargestellt werden kann, dann bin ich mir nicht einmal sicher, ob der Compiler es genau in long double konvertieren könnte - wahrscheinlich nicht, weil diese Konvertierung vor alles, was von FLT_EVAL_METHOD abgedeckt wird. Es besteht keine Anforderung, dass eine höhere Genauigkeit konsistent verwendet werden muss.

Es gibt zwei Stellen, an denen die Umwandlung in das Doppelte stattfinden muss: An der Stelle der Besetzung (doppelt) und an der Stelle der Zuweisung zu einem Doppel. Es gab GCC-Versionen, bei denen die Besetzung zum Verdoppeln "optimiert" wurde, wenn ein Wert bereits "offiziell" ein Doppel war (wie xi * xd hier), selbst wenn es in Wirklichkeit eine höhere Genauigkeit war; Diese "Optimierung" war immer ein Fehler, weil ein Cast konvertiert werden muss.

Sie könnten also auf diesen Fehler gestoßen sein, bei dem eine Doppelbesetzung nicht durchgeführt wurde (wenn der Fehler immer noch vorhanden ist), haben Sie möglicherweise eine inkonsistente Verwendung höherer Genauigkeit festgestellt, die zulässig ist, wenn FLT_EVAL_METHOD dies zulässt, und Sie möglicherweise sogar inkonsistente Verwendung höherer Genauigkeit, wenn FLT_EVAL_METHOD es überhaupt nicht erlaubte, was wiederum ein Fehler wäre (nicht die Inkonsistenz, sondern die Verwendung höherer Genauigkeit an erster Stelle).

    
gnasher729 21.12.2015 08:56
quelle