[c++] clang und gcc49 Programme erzeugen unterschiedlichen Output

Kamikaze

Warrior of Sunlight
Teammitglied
Bei Double-precision FP Operationen habe ich bis zu 2 Bit Unterschied im Output meiner Programme. Und zwar ohne -ffast-math.

Das ist so eigentlich nicht zulässig, oder?
 
Diese Unterschiede siehst Du aber nur bei Rechnungen mit etlichen Rechenschritten!? Die IEEE bzw. ISO-Regeln regeln nicht bis ins letzte Detail, wie genau mathematische Operationen durchzuführen sind bzw. in welcher Reihenfolge. Da treten dann natürlich unvermeidbar die Folgen der begrenzten Stellenzahl der Zwischenergebnisse zutage und wirken sich früher oder später auch auf zwei oder mehr Bits aus. Auch ohne -ffast-math.
So etwas wie sqrt(2) darf aber keine zwei Bits Unterschied aufweisen - hoffe ich doch!
 
Da stecken deutlich mehr Rechenschritte drin. Zuerst werden 4x4 Matrizen zusammenmultipliziert und damit wiederum Vektoren. Da hat man ja für jede Dimension des Vektors 4 Rechenschritte. Dann werden da noch Mittels Gauss Schnittpunkte mit den aufgespannten Flächen bestimmt … Ich würde mal sagen zwischen den Eingabedaten und den Ausgangsdaten stehen so 10 bis 20 Rechenschritte.

Ich habe die sin() und cos() Taylorreihen übrigens selbst noch mal neu implementiert, weil ich nirgendwo Garantien bezüglich Genauigkeit gefunden habe.
 
Manche C-Compiler haben keine Funktionen für Single-Precision (sinf, cosf) und mappen diese auf Double-Routinen, einfach so (nur um ein Beispiel zu benennen). Also Du kannst Dir vorstellen was da für eine Genauigkeit verlangt wird. Ich habe außerdem ständig Ärger mit verschiedenen Plattformen. Da kommen oft große Ungenauigkeiten vor, schon im Promillebereich bei einfachen Rechnungen.

Du kannst ja auch Ungenauigkeiten überwachen, siehe fenv(3).
 
Zumindest bei einfachen Rechnungen, wo es für den Compiler nichts an der Reihenfolge zu drehen gibt, sollten doch Ergebnisse garantierbar sein. Hätte ich zumindest so erwartet.
 
Da stecken deutlich mehr Rechenschritte drin. Zuerst werden 4x4 Matrizen zusammenmultipliziert und damit wiederum Vektoren. Da hat man ja für jede Dimension des Vektors 4 Rechenschritte. Dann werden da noch Mittels Gauss Schnittpunkte mit den aufgespannten Flächen bestimmt … Ich würde mal sagen zwischen den Eingabedaten und den Ausgangsdaten stehen so 10 bis 20 Rechenschritte.

Ich habe die sin() und cos() Taylorreihen übrigens selbst noch mal neu implementiert, weil ich nirgendwo Garantien bezüglich Genauigkeit gefunden habe.

Benutzt du die MTL dafür? Ich denke das wird dir viel arbeit abnehmen und dabei noch schneller sein.
 
Wie ist das denn im wissenschaftlichen Bereich, gibt es dort spezielle Compiler, die mit astronomischen Nachkommastellen umgehen können? Solche Abweichungen, wenn es um größere Distanzen geht, würde ja das Ergebnis signifikant verfälschen. Spontan fällt mir da die Weltraumforschung ein ...
 
Wie ist das denn im wissenschaftlichen Bereich, gibt es dort spezielle Compiler, die mit astronomischen Nachkommastellen umgehen können? Solche Abweichungen, wenn es um größere Distanzen geht, würde ja das Ergebnis signifikant verfälschen. Spontan fällt mir da die Weltraumforschung ein ...

Wenn es darauf ankommt geht es darum schon die Rechnungen so zu machen, dass möglichst wenig Rundungsfehler passieren. Das ist dann auf einmal viel relevanter als die konkrete Maschinengenauigkeit -> Kondition und Stabilität.

edit: wie im oben verlingten Post kurz erwähnt ist das aber was anderes als Reproduzierbarkeit und impliziert diese auch nicht.
 
Wenn Du Bock hast auf Formales und Ungenauigkeiten nicht tolerierst, dann würde ich Haskell in Erwägung ziehen. Da gibt es Zahlen in der Form, dass der Speicher die Einschränkung ist. Integer hat keine Grenzen (!= Int), Rational ist ein Quotient mit dem man Rechnet und CReal sind konstruktive reelle Zahlen.

So schwierig ist die Sprache auch nicht, insbesondere ein Informatiker sollte sie kennen (meine Meinung).
 
Benutzt du die MTL dafür? Ich denke das wird dir viel arbeit abnehmen und dabei noch schneller sein.
Nein tue ich nicht. Ich denke das würde auch nicht viel bringen, meine Vektor-Klassen sind schon so geschrieben, dass die größtenteils weg optimiert werden, i.e. fast komplett inline.

Ich mache aber die Unterscheidung zwischen Punkt und Richtungsvektoren und meine eigene Implementierung erlaubt mir hier so sachen wie Punkt - Punkt → Richtung, oder Matrix * Punkt ergibt etwas anderes als Matrix * Richtung. Bei Richtungsvektoren ignoriere ich nämlich die 4. Spalte der Matrix.

Punkt + Punkt ist in meiner Implementierung verboten, dafür gibt es ein Variadic template Point::centre(), das den Mittelpunkt aus einer Liste von Punkten generiert.

Wie gut das Inlinen funktioniert sieht man an meinem Standardtestfall:
Code:
| Optimization | Real [s] | User [s] | Sys [s] |
| -O0          | 77.40    | 77.19    | 0.17    |
| -Os          | 24.21    | 24.08    | 0.12    |
| -O1          | 42.95    | 42.82    | 0.11    |
| -O2          | 23.04    | 22.95    | 0.07    |

Zwischen -O0 und -O2 liegt ein Faktor > 3. Mit -march=native wird es noch etwas schneller.
 
Zuletzt bearbeitet:
Wie ist das denn im wissenschaftlichen Bereich, gibt es dort spezielle Compiler, die mit astronomischen Nachkommastellen umgehen können? Solche Abweichungen, wenn es um größere Distanzen geht, würde ja das Ergebnis signifikant verfälschen. Spontan fällt mir da die Weltraumforschung ein ...
Wenn Du bei C/C++ bleibst gibt es Bibliotheken wie GMP dafür.

Ich habe mir ein Template WideInteger geschrieben, damit ich Voxel, bzw. Volumen in Voxel zählen kann (dafür brauche ich im Worst case 189 Bits). Damit kann ich nur 8er Potenzen hinzuaddieren (also 1, 8, 64, …). Außerdem gibt es eine operator um auf double zu casten (O(n)) und einen auf string (O(n²)).

Für meine Zwecke wäre fixed Precision Arithmetik besser geeignet. Da hätte man in einem begrenzten Zahlenraum überall die gleiche Genauigkeit.

Da die aber nicht direkt von den CPUs unterstützt wird ist das von der Performance her nicht praktikabel.
 
Ich habe vor 15 (?) Jahren mal (im Spektrum der Wissenschaft, IIRC) über ein Forschungsprojekt an einer deutschen Uni gelesen. Da haben sie selbst einen Prozessor gebaut, der neben "gewöhnlichen" Gleitkomma-Registern ein superlanges Register hatte mit vielen hundert Bits. Damit (und mit ein wenig Theorie über Numerik und Arithmetik) konnten sie viele lästige Numerik-Probleme, z. B. mit beinahe-singulären Matrizen, elegant erledigen. Leider fiel die Idee offenbar nirgends auf fruchtbaren Boden.
 
Zurück
Oben