Unterschiedliches ergebnis für float und double



  • Hallo,
    warum ist das Ergebnis von folgenden Funktionen für floats nicht gleich? Bei Double ist es aber gleich

    Ich benutze gcc 3.4.2 (gnauergesagt mingw). Fall es wichtig ist.

    template <typename T>
    T calc1(T a, T b, T c)
    {
       T t = a*a + b*b + c*c;
       t = std::sqrt(t); //<-- Hier ist der Unterschied
       a /= t; //<-- Hier ist der Unterschied
       b /= t; //<-- Hier ist der Unterschied
       c /= t; //<-- Hier ist der Unterschied
       return a + b + c;
    }
    
    template <typename T>
    T calc2(T a, T b, T c)
    {
       T t = a*a + b*b + c*c;
       t = (T)1.0/std::sqrt(t);  //<-- Hier ist der Unterschied
       a *= t; //<-- Hier ist der Unterschied
       b *= t; //<-- Hier ist der Unterschied
       c *= t; //<-- Hier ist der Unterschied
       return a + b + c;
    }
    

    Wenn ich dann aufrufe:

    bool res = // res ist hier 0
    calc1<float>(2.0f, 3.0f, -5.0f) == calc2<float>(2.0f, 3.0f, -5.0f);
    res = // res ist hier 1
    calc1<double>(2.0f, 3.0f, -5.0f) == calc2<double>(2.0f, 3.0f, -5.0f);
    

    Die calc2<float>() liefert offensichtlich ein falsches Ergebnis. Aber warum? 1.0 /sqrt(t) ist nicht besonders klein. Ca 0.162.
    Leider ist aber gerade dieser Algorithmus den ich haben möchte. Da, eine Division und drei multiplikationen imho schneller sind als drei divisionen.

    Oder sollte ich komplett auf double umsteigen?



  • du darfst fließkommazahlen nicht vergleichen. das sind immer nur gerundete werte, da sehr viele zahlen nicht exakt darstellbar sind.

    besser wäre:

    calc1<float>(2.0f, 3.0f, -5.0f) - calc2<float>(2.0f, 3.0f, -5.0f) <= 0.001f
    


  • Dieser Ansatz würde zwar funktionieren. Aber die Ungenauigkeit ist immer noch vorhanden. Und sie ist nicht gerade klein.

    Ich weiß dass man nicht in einem frühen Stadium auf schnellen Code achten sollte. Aber (1) Es wird eine Lib. D.h. ich kann jetzt nicht abschätzen wie oft so ein Vergleich stattfindet. Und (2) mit deiner Methode wäre das doch um einiges langsamer. V.a. wenn man berücksichtigt, dass die Differenz auch negativ sein kann.

    Wenn es keine andere Möglichkeit gibt, dann bleibt mir wohl nichts anderes übrig als so einen Mindestwert (Epsilon?) zu verwenden.

    Oder soll ich double verwenden, obwohl die Abweichung für float nur ca. 3e-8 beträgt. Oder ist das anwendungsspeziefisch und ich sollte lieber ein Template anbieten und für "spezielle" Anforderungen einen 1Mb-großen Datentyp implementieren 😉


Anmelden zum Antworten