Frage zu Ungenauigkeit bei Fließkommazahlen



  • So?



  • std::numeric_limits<float>::epsilon() liegt in der Größenordnung 10^-7, was sagt das aus über zwei floats in der Größenordnung 10^10? Was für zwei floats in der Größenordnung 10^-24?



  • Wo ist das Problem? Die Frage ist doch, wann zwei float Werte als gleich angesehen werden können, und wenn man die Differenz von zwei float Werten bildet spielen die absoluten Grössen keine Rolle mehr, weil man die Differenz mit epsilon vergleicht.



  • Du meinst also, dass 1e-20 und 1e-30 gleich sind?



  • @Bashar Sofern epsilon > 1e-20 ist, ja!

    Das ganze hier ist eine Grenzwertbetrachtung und wer in Mathe nicht aufgepasst hat, versteht das nicht. Es gilt
    a + e == a

    Das Epsilon kannst du manuell berechnen (C#)

    double tau = 1.0;
    double walt = 1.0;
    double wneu = 0.0;
    
    while (wneu != walt)
    {
    	tau *= 0.5;
    	wneu = walt + tau;
    }
    
    return 2.0 * tau;
    

    Quelle: http://dotnet-snippets.de/dns/c-maschinengenauigkeit-SID961.aspx

    Gruß,
    Thomas



  • @Siassei: Mach dich nicht zum Obst... Denk lieber noch mal nach...

    epsilon *2^potenz würde (ganz grob gesehen) vll gehen, aber nur epsilon def. nicht, weil es eben eine _gleit_kommazahl ist...



  • Siassei schrieb:

    @Bashar Sofern epsilon > 1e-20 ist, ja!

    Epsilon ist für float ungefähr 1e-7.

    Das ganze hier ist eine Grenzwertbetrachtung und wer in Mathe nicht aufgepasst hat, versteht das nicht.

    Nein, es ist keine Grenzwertbetrachtung.

    Es gilt
    a + e == a

    Für a >= 2, ja.



  • Touché... und jetzt frage ich mich, wofür epsilon() und denorm_min() überhaupt gut sind. epsilon() ist mit 1.9E-7 deutlich zu gross und denorm_min() mit ~1.41E-45 liegt ausserhalb des float Wertebereichs...


  • Mod

    DocShoe schrieb:

    Touché... und jetzt frage ich mich, wofür epsilon() und denorm_min() überhaupt gut sind. epsilon() ist mit 1.9E-7 deutlich zu gross und denorm_min() mit ~1.41E-45 liegt ausserhalb des float Wertebereichs...

    Das epsilon gibt dir einen Anhaltspunkt, wieviele zählende Stellen die Fließkommazahl hat. Und denorm_min ist wie der Name schon sagt die kleinste darstellbare Zahl.

    Immer daran denken, dass eine Fließkommazahl einen normalen Zahlenteil (die Mantisse) und einen Exponententeil hat. Das epsilon beschreibt dir die Genauigkeit der Mantisse und das denorm_min die Genauigkeit des Exponenten.


  • Mod

    static T epsilon() throw();
    20 Machine epsilon: the difference between 1 and the least value greater than 1 that is representable.

    Anders ausgedrückt:
    a!=b g.d.w. a/b >= e/radix , mit normalen a,b: a > b > 0
    es ist damit die Obergrenze für den relativen Fehler einer normalisierten Zahl.

    Nicht, dass klar wäre, wieso diese Diskussion hier geführt werden muss. Mit der Ausgangsfrage hat das nichts zu tun. Und irgendwelche vagen Hinweise auf FPUs helfen hier auch nicht.

    Nur weil jemand dem Compiler nicht traut, führt das zweifellos nicht zur Lösung.



  • camper schrieb:

    static T epsilon() throw();
    Machine epsilon: the difference between 1 and the least value greater than 1 that is representable.

    Anders ausgedrückt:
    a!=b g.d.w. a/b >= e/radix , mit normalen a,b: a > b > 0

    Du meinst wohl abs(a/b-1).

    Finde es aber schon komisch, dass Du != unter Verwendung von / und >= "definierst".

    Ich weiß nicht, welche Garantien hier wirklich gemacht werden, aber man sollte doch meinen, dass die Vergleichsoperatoren auf Floatingpoint-Zahlen genauso funktionieren, wie man es erwartet: nämlich einfach die Werte vergleichen, die durch die Bitmuster repräsentiert werden.

    Gruß,
    SP


  • Mod

    Sebastian Pizer schrieb:

    Du meinst wohl abs(a/b-1).

    Finde es aber schon komisch, dass Du != unter Verwendung von / und >= "definierst".

    ja, -1
    Allerdings soll das keine Definition von != sein, sondern einer Erläuterung hinsichtlich des Sinns von epsilon.

    TGGC schrieb:

    Sebastian Pizer schrieb:

    nämlich einfach die Werte vergleichen, die durch die Bitmuster repräsentiert werden.

    Womit wir wieder beim eigentlichen Problem sind, schreibt jede Hardware in jedem Zustand fuer einen Wert immer genau das gleiche Bitmuster in den Speicher und liest sie aus jedem Bitmuster im Speicher immer genau den gleichen Wert? Wenn man etwas davon durch die moeglichen Rundungsmodi etc. beeinflussen kann, dann kann die oben genannte Aktion scheitern.

    Beispiel? Hardware ist hier nicht besonders relevant; jedenfalls scheint hier eine merkwürdige (ohne gar keine) Vorstellung von "Wert" zu bestehen. (Implizite) Rundung tritt grundsätzlich dann auf, wenn ein Wert eines bestimmten Typen T in einen Wert des Typs U != T umgewandelt werden muss, und nicht jeder mögliche Wert des Typs T exakt durch einen Wert des Typs U dargestellt werden kann. Bei einer Zuweisung eines Wertes an eine Variable des gleichen Typs ist für Rundung schlicht weder Veranlassung noch Platz.
    Wird der (wohldefinierte - keine Traprepräsentation) Wert einer POD-Variablen a einer anderen Variablen b gleichen Typs zugewiesen, so sind im Anschluss die Werte beider Variablen äquivalent: in jedem Ausdruck, der nur vom Wert der Variablena abhängt, kann nach Belieben jede Instanz von a durch b ersetzt werden, ohne dass sich der Wert des Ausdrucks ändert.
    Die Frage des OP ist insoweit positiv zu beantworten: der Vergleich der Variablen mit == wird immer true ergeben soweit == Äquivalenzrelation ist.
    Der Vergleich zwischen einem NaN und einem beliebigen anderen Wert führt immer zum Ergebnis ungleich; insoweit ist == keine Äquivalenzrelation.



  • camper schrieb:

    Der Vergleich zwischen einem NaN und einem beliebigen anderen Wert führt immer zum Ergebnis ungleich; insoweit ist == keine Äquivalenzrelation.

    Das sehe ich gerade nicht. Meinste Du "Der Vergleich zwischen einem NaN und einem beliebigen Wert" oder wie geschrieben "Der Vergleich zwischen einem NaN und einem beliebigen anderen Wert"?


  • Mod

    volkard schrieb:

    camper schrieb:

    Der Vergleich zwischen einem NaN und einem beliebigen anderen Wert führt immer zum Ergebnis ungleich; insoweit ist == keine Äquivalenzrelation.

    Das sehe ich gerade nicht. Meinste Du "Der Vergleich zwischen einem NaN und einem beliebigen Wert" oder wie geschrieben "Der Vergleich zwischen einem NaN und einem beliebigen anderen Wert"?

    ja, danke. Entscheidend ist hier der Vergleich des Wertes mit sich selbst, der ungleich liefert.



  • volkard, was soll der Quatsch schon wieder? f'`8k

    Autocogito

    Gruß, TGGC (Was Gamestar sagt...)



  • TGGC schrieb:

    Sebastian Pizer schrieb:

    nämlich einfach die Werte vergleichen, die durch die Bitmuster repräsentiert werden.

    Womit wir wieder beim eigentlichen Problem sind, schreibt jede Hardware in jedem Zustand fuer einen Wert immer genau das gleiche Bitmuster in den Speicher

    Ich verstehe ehrlich gesagt nicht, was Du damit sagen willst. Das liegt wahrscheinlich daran, dass wir unter "Zustand", "Wert", "Bitmuster" etwas anderes verstehen. Dass Du zwischen "Zustand" und "Bitmuster" unterscheidest irritiert mich gerade.

    Der C++ Standard spricht hier von "object representation" und "value representation". Ferner: "For POD types, the value representation is a set of bits in the object representation that determines the value, which is one discrete element of an implementation-defined set of values."

    Und "implementation-defined" sagt schon mal viel aus. Diese Wertemenge kann man ja definieren, wie man will. Sind +0 und -0 zwei "verschiedene" Elemente dieser Menge? Wenn ja, wie ist die Ordnung definiert? -0 < +0 oder -0 == +0? Bei IEEE754 wird zwischen -0 und +0 unterschieden (ein Unterlauf erhält das Vorzeichen) wobei aber -0 und +0 als gleichwertig (bzgl Vergleichsoperatoren) betrachtet werden.

    Gruß,
    SP



  • ich fand eigtl tggc`s post gar nicht so uninteressant, hatte den tab aber scho wieder geschlossen, bevor ich ihn richtig lesen konnte...
    wenn er das hier liest, postet er es vll noch mal!? 😉
    vll wirds diesmal auch nicht gleich gelöscht :|



  • Also so wie ich es verstehe:
    Mit Zustand der Hardware, meine ich so etwas wie man es z.b. hiermit einstellt: http://msdn.microsoft.com/en-us/library/e9b52ceh(VS.80).aspx . Ich weiss, das hat mit dem "theoretischem C++ Verhalten" nichts zu tun. Aber in der Praxis werden deine Floating Point Berechnungen ja doch auf irgendeiner Hardware ausgefuehrt. Bitmuster ist der Zustand des floats im RAM bzw. auf HD. Wert ist das was die FPU nun in ihrem aktuellen Zustand unter diesem Bitmuster versteht. Und worauf ich hier hinaus will, ist das ein Wert auch gleichzeitig eine gewisse Genauigkeit hat. Wenn ein float in die FPU geladen wird, dann kann es gut sein das quasi aus einer 1,25 ein 1,25000 wird. Es koennte aber auch ein 1,25000000 sein. "float" gibt hier nur eine minimale Genauigkeit vor, die FPU koennte und wird standardmaessig aber intern eine hoehere Genauigkeit benutzen. Nur weiss man als Programmierer nicht mal wie genau der Optimierer Zwischenwerte auf der FPU (und damit in hoeherer Praezision) haelt und hat damit keine Kontrolle ueber diesen Vorgang. f'`8k

    Autocogito

    Gruß, TGGC (Was Gamestar sagt...)



  • TGGC schrieb:

    Aber in der Praxis werden deine Floating Point Berechnungen ja doch auf irgendeiner Hardware ausgefuehrt. Bitmuster ist der Zustand des floats im RAM bzw. auf HD. Wert ist das was die FPU nun in ihrem aktuellen Zustand unter diesem Bitmuster versteht. Und worauf ich hier hinaus will, ist das ein Wert auch gleichzeitig eine gewisse Genauigkeit hat. Wenn ein float in die FPU geladen wird, dann kann es gut sein das quasi aus einer 1,25 ein 1,25000 wird. Es koennte aber auch ein 1,25000000 sein. "float" gibt hier nur eine minimale Genauigkeit vor, die FPU koennte und wird standardmaessig aber intern eine hoehere Genauigkeit benutzen. Nur weiss man als Programmierer nicht mal wie genau der Optimierer Zwischenwerte auf der FPU (und damit in hoeherer Praezision) haelt und hat damit keine Kontrolle ueber diesen Vorgang.

    Doch. dafür gibt es: http://en.wikipedia.org/wiki/Volatile_variable



  • Ok, wenn du das Kontrolle nennst, ich nenne es Einschraenkung. Der Code wird dadurch laenger und langsamer. Du kannst weder kontrollieren, welche Genauigkeit die FPU nun intern benutzt (der Standard kennt das nicht, AFAIK). Noch ist es moeglich zu sagen: innerhalb dieser Berechnung, soll immer alles auf der FPU bleiben. Das erste fuehrt zu Unterschieden auf verschiedenen Plattformen, das zweite sogar zu Unterschieden von Debug und Releasebuilds auf der gleichen Maschine (bzw. Builds verschiedener Optimierungsstufen). f'`8k

    Gruß, TGGC (Was Gamestar sagt...)


Anmelden zum Antworten