Fließkommaungenauigkeit?
-
@Nexus:
Ja ich benutze den normalen == operator gar nicht mehr sondern eine epsilon-Funktion ... sonst würde gar nichts gehen.
Wie ist den boost.rational? Ich habe eine zeitkritische Anwendung... (zumindest wird sie das
)
-
floater schrieb:
Was lässt sich berechnen? Die Abweichung?
Japp - lässt sich berechnen... würd ich aber nicht versuchen, weils nich ganz einfach ist^^ und lässt sich auch nur so lange berechnen, wie du die genaue reihenfolge aller operationen kennst...
ansonsten kanns auch oft sein, dass du mit ganzen zahlen besser kommst, die du um x stellen verschiebst... kommt eben auf die anwendung drauf an ^^
bb
ansonsten:
boost-rational wird bei den meisten operationen nat ein wenig langsamer sein - aber du gibst so wenige informationen, dass man irgendwie gar nichts weiß und auch gar nich iwie helfen kann, weil man selbst nur raten müsste
-
Das ist eine Bruch-Klasse, die exakt rechnet. Sie ist recht effizient implementiert, aber
floats werden wohl schon schneller sein. Kommt halt drauf an, wie wichtig dir exakte Werte im Vergleich zu Performance sind.
-
Ich rechne sehr viel mit Ebenen Geraden und dergleichen im R3.
Und Rundungsfehler sind schnell sichtbar.... schon seit Monaten versuche ich das zu beheben.... Das A und O ist Exaktheit!!
Also rechne ich einfach mit boost::rational<int>?
Tests laufen schon ^^
-
Folgendes Problem:
Ich habe immer floats als Ausgangswerte (3 Vektoren)
Nun kann ich die doch nicht ohne weiteres umwandeln!
Wenn ich nun mit rational<float> rechne werden Rundungsfehler dennoch auftreten?!
Das wird eine Weile dauern bis ich rational im Programm implementiert habe ... deshalb frage ich shconmal
-
floater schrieb:
Entschuldigt bitte diese doofe Frage, aber einige Zahlen kann der PC nicht gut darstellen?
So'ne Fließkommazahl besteht ja meistens "nur" aus 32 oder 64 Bit. Reelle Zahlen gibt es aber unendlich viele. Also kannst Du gar nicht jede Zahl exakt darstelen. Da der Rechner ein (meist) ein binär-basiertes System benutzt kann so ein Zehnerbruch schonmal komisch aussehen:
Dezimal: 0,4 Binär: 0,011001101...Jedes Fließkomma-Format hat aber eine sogenannte Maschinengenauigkeit
epsilon. Sie gibt Dir an, wie genau eine Zahl repräsentiert werden kann -- abgesehen von betragsmäßig extrem großen Zahlen (wie 10^300), oder Zahlen, die extrem nah an 0 sind (wie 10^-300). Seixdas exakte Ergebnis einer Rechenoperation (+,-,*,/) oder die Eingabe, seiyder Wert den eine Fließkommavariable nach einer Zuweisung von x hat, dann gilt:|x-y| <= y * epsilon(Der relative Fehler ist durchepsilonbeschränkt.)Die Fehler pflanzen sich aber auch fort. Beispielsweise: Bei einer Addition oder Subtraktion addieren sich die absoluten Fehler der Operanden. Bei einer Multiplikation oder Division addieren sich die relativen Fehler der Operanden.
Wieder C++-Spezifisch: Du kannst das epsilon über std::numeric_limits<T>::epsilon() für jeden Fließkommatyp T erfragen. Zu finden ist dieses Klassentemplate im
<limits>Header.Gruß,
SP
-
floater schrieb:
Ich rechne sehr viel mit Ebenen Geraden und dergleichen im R3.
Und Rundungsfehler sind schnell sichtbar.... schon seit Monaten versuche ich das zu beheben.... Das A und O ist Exaktheit!!Du kannst ja mal GMP versuchen (GNU Multiple Precision library). Die haben auch nen leichtbenutzbaren C++ Header und die Klasse mpq_class (für rationale Zahlen mit beliebig großen Zähler und Nenner).
Mit boost::rational<int> kommt Du wahrscheinlich relativ schnell zu einem Überlauf. Ich würde mich auch gar nicht auf boost::rational<long long> verlassen. Einen float kannst Du da auch nicht benutzen.
Gruß,
SP
-
floater schrieb:
Folgendes Problem:
Ich habe immer floats als Ausgangswerte (3 Vektoren)
Nun kann ich die doch nicht ohne weiteres umwandeln!
Wenn ich nun mit rational<float> rechne werden Rundungsfehler dennoch auftreten?!
Das wird eine Weile dauern bis ich rational im Programm implementiert habe ... deshalb frage ich shconmal
Du bekommst viel gemeinere Probleme mit Bruchzahlen:
x=1/2; x=x*5/6; x=x*5/6; x=x*5/6; x=x*5/6; x=x*5/6; x=x*5/6; x=x*5/6;Die Zähler und Nenner wachsen im Verlauf der Schleifen ins Unermessliche und das Prog wird entweder (mit Riesenintegers) arschlahm oder auch ungenau.
Vermutlich ist es besser, Du achtest drauf, keine Fehleransammlungen zu bauen (das Standardbeispiel dazu ist, daß man nicht die Eckpunkte des Körpers pro Schleifendurchlauf winzig ändert und erlaubt, daß die Ecken verschmieren, sondern daß man nur die Position und deen Winkel des Gesamtkörpers und in jedem Schleifendurchlauf alle Ecken neuberechnet) oder daß die Fehleransammlungen nicht auffallen (wen juckt's, daß der char pro Schritt ein handbreit danebenlatscht, zwei sich in einem Punkt treffende Ebenen teilen sich den selben Punkt über Zeiger?) oder daß die Fehleransammlungen nicht explodieren können (immer wieder mal die Einheitsvektoren schrubben)...
-
Das mit den Brüchen stimmt, ist hier wohl keine gute Idee. Ich hatte bisher nur Anwendungsfälle, bei denen Zähler und Nenner klein blieben.
floater, wieso nimmst du eigentlich
float, wenn die Genauigkeit entscheidend ist? Mitdoubleoderlong doublekönnte sich bereits einiges verbessern, auch wenn das nicht der Weisheit letzter Schluss ist.
-
Nexus schrieb:
Das mit den Brüchen stimmt, ist hier wohl keine gute Idee. Ich hatte bisher nur Anwendungsfälle, bei denen Zähler und Nenner klein blieben.
floater, wieso nimmst du eigentlich
float, wenn die Genauigkeit entscheidend ist? Mitdoubleoderlong doublekönnte sich bereits einiges verbessern, auch wenn das nicht der Weisheit letzter Schluss ist.Würde das das Problem nicht einfach nur verlagert werden? Rechenfehler werden dennoch auftreten die irgendwann zu einem Fehler führen. Ich dachte halt dass ein stabiler Algorithmus auch float verträgt?
-
floater schrieb:
Ich dachte halt dass ein stabiler Algorithmus auch float verträgt?
Jo.
Fehlerverstärkende Algos lassen den Fehler meistens exponentiell wachsen, wenn der mit float nach 3 Minuten über die Maßen häßlich wird, dauert's bei double halt 6 Minuten. Das ist nicht lecker.
Manchmal hat man einen Algo, der Fehler nur ansammelt, aber nicht verstärkt, da würde double eine erhebliche Verbesserung bringen. Aber fraglich ist, ob dabei der Fehler bei float überhaupt schon sichtbar wäre. Und zu bedenken ist, daß eine Stunde Spielzeit verdammt viele Frames zeigt. Leider ist diese Sorte Fehler nicht vermeidbar. Aber wenn sie eh versteckt, geschrubbt und geeignet ignoriert werden, kann man ja eh von double wieder runter auf float.
-
Wie kann ich die Fehlergröße eingrenzen? Also gibt es eine Methode um das Epsilon zu bestimmen? Ich treffe bis jetzt mehr oder weniger blinde Vrorkehrungen!
-
floater schrieb:
Wie kann ich die Fehlergröße eingrenzen? Also gibt es eine Methode um das Epsilon zu bestimmen?
->
Die Fehler pflanzen sich aber auch fort. Beispielsweise: Bei einer Addition oder Subtraktion addieren sich die absoluten Fehler der Operanden. Bei einer Multiplikation oder Division addieren sich die relativen Fehler der Operanden.
Wieder C++-Spezifisch: Du kannst das epsilon über std::numeric_limits<T>::epsilon() für jeden Fließkommatyp T erfragen. Zu finden ist dieses Klassentemplate im <limits> Header.
Oder was meinst du mit bestimmen?
Ich treffe bis jetzt mehr oder weniger blinde Vrorkehrungen!
Wie das denn?
bb
-
Ja habe per trial&error 20*std::numeric_limits<float>::epsilon() für mein Programm als am Besten ermittelt.
Das funktioniert jedoch nicht immer und in der Regel ist der Wert auch unnötig groß.
Ich frage mich daher ob man je nach Rechenoperation die Ungenauigkeit auf wenigstens die Stellenzahl begrenzen kann...