float vs double



  • @wob sagte in float vs double:

    Wobei: du solltest selbst checken, was dein Compiler generiert hat.

    Das sagt mit jetzt auf die Schnelle leider nichts. Wie mache ich das?

    Habe den Code zu

    double doubleTest()
    {
        double a = 1000, b = 45, c = 12000, d = 2, e = 7, f = 1024;
        double a_ = std::sin( a );
        double b_ = std::asin( b );
        double c_ = std::sqrt( c );
        double d_ = d + d - d + d;
        double e_ = e * e + e * e;
        double f_ = f / f / f / f / f;
    
        return a_ / b_ / c_ / d_ / e_ / f_;
    }
    
    float floatTest()
    {
        float a = 1000, b = 45, c = 12000, d = 2, e = 7, f = 1024;
        float a_ = std::sin( a );
        float b_ = std::asin( b );
        float c_ = std::sqrt( c );
        float d_ = d + d - d + d;
        float e_ = e * e + e * e;
        float f_ = f / f / f / f / f;
    
        return a_ / b_ / c_ / d_ / e_ / f_;
    }
    
    int main()
    {
        stopwatch timer( resolution::ms );
        const int loops = 1000000;
    
        std::cout << "\ndouble: ";
        timer.start();
        for ( int i = 0; i < loops; ++i )
        {
            double d = doubleTest();
        }
        timer.stop();
        std::cout << "\nloops: " << loops << "  time: " << timer.elapsed() << " ms\n";
    
        std::cout << "\nfloat: ";
        timer.start();
        for ( int i = 0; i < loops; ++i )
        {
            float f = floatTest();
        }
        timer.stop();
        std::cout << "\nloops: " << loops << "  time: " << timer.elapsed() << " ms\n";
    }
    

    geändert. Abgesehen von den ungenutzten d und f in der main, wäre dies sinnvoller?
    Und wenn ja, wäre nicht noch sinnvoller, lieber random-Werte in den Funktionen zu nehmen, statt vorgegebene?



  • @lemon03 sagte in float vs double:

    @wob sagte in float vs double:

    Wobei: du solltest selbst checken, was dein Compiler generiert hat.

    Das sagt mit jetzt auf die Schnelle leider nichts. Wie mache ich das?

    Indem Du Dir den Assemblercode anschaust, den Dein Compiler ausspuckt.

    @lemon03 sagte in float vs double:

    for ( int i = 0; i < loops; ++i )
    {
        double d = doubleTest();
    }
    

    und analog auch die Schleife für float kann ein Compiler wieder komplett Wegoptimieren, da sie keine Seiteneffekte hat. Besser:

    double d{};
    for ( int i = 0; i < loops; ++i )
    {
        d += doubleTest();
    }
    std::cout << d << '\n';
    


  • @swordfish sagte in float vs double:

    Indem Du Dir den Assemblercode anschaust, den Dein Compiler ausspuckt.

    Gibts da ein Tool vor, oder kann ich das online machen, wie es manchmal gezeigt wird?
    Und wenn ich jetzt gar keine Ahnung von Assembler habe, schaue ich dann einfach, was weniger Zeilen hat?

    ok, mach ich mal.



  • @lemon03 sagte in float vs double:

    Gibts da ein Tool vor, oder kann ich das online machen, wie es manchmal gezeigt wird?

    "wie es manchmal gezeigt wird?" ?
    Codebolt ist ganz praktisch, um verschiedenen Compilern beim Arbeiten zuzusehen. Färbt auch praktischerweise Sourcecodezeile und zugehörige Assembleranweisungen in der selben Farbe ein.

    @lemon03 sagte in float vs double:

    Und wenn ich jetzt gar keine Ahnung von Assembler habe, schaue ich dann einfach, was weniger Zeilen hat?

    Einen Funktionsaufruf oder Addition, Subtraktion, Multiplikation oder Division wirst Du wohl erkennen?



  • Mit

        stopwatch timer( resolution::ms );
        const int loops = 1000000;
    
        double d{};
        std::cout << "\ndouble: ";
        timer.start();
        for ( int i = 0; i < loops; ++i )
        {
            d += doubleTest();
        }
        timer.stop();
        std::cout << "\nloops: " << loops << "  time: " << timer.elapsed() << " ms\n";
    
        float f{};
        std::cout << "\nfloat: ";
        timer.start();
        for ( int i = 0; i < loops; ++i )
        {
            f += floatTest();
        }
        timer.stop();
        std::cout << "\nloops: " << loops << "  time: " << timer.elapsed() << " ms\n";
    

    komme ich auch wieder auf

    double:
    loops: 1000000  time: 63.3185 ms
    
    float:
    loops: 1000000  time: 29.4841 ms
    

    Sollte ich wohl ein "lebensnäheres" Beispiel nehmen?



  • @swordfish sagte in float vs double:

    Einen Funktionsaufruf oder Addition, Subtraktion, Multiplikation oder Division wirst Du wohl erkennen?

    Eigentlich, keine Ahnung. Müsste ich mal Assemblercode sehen, ob ich entsprechendes erkennen kann. Hab zwar schon öfter welchen gesehen, aber man müsste mir schon sagen, was dort was sein soll.
    Hast ja ein Beispiel gebracht. Kann ich ja mal nachschauen.



  • @lemon03 sagte in float vs double:

    komme ich auch wieder auf

    f bzw. d wird ja nach der Schleife wieder nicht verwendet. Ich als Compiler würd mir also denken: "Aufsummieren?? Wozu?? Ich bin doch nicht sein Trottel ... braucht das Ergebnis sowieso nicht!".

    Aber alles was wir hier diskutieren ist graue Theorie. Welcher Compiler? Welche Platform?



  • Compiler ist gcc. Plattform ist win10x64. Gemeint?

    Bei meiner Suche wurde schon erwähnt, das es auch einen Unterschied gibt zwischen x86 und x64. Dann aber wieder nicht. Der Schluss ist immer "hängt davon ab...".

    Der Ordner in meinem MinGW lautet x86_64-w64-mingw32.



  • PS:

    @swordfish sagte in float vs double:

    f bzw. d wird ja nach der Schleife wieder nicht verwendet.

    Ups, habe ich verpennt... Jetzt erst gesehen.



  • Hier noch einmal ein vollständiger Test mit std::chrono:

    #include <iostream>
    #include <cmath>
    #include <chrono>
    
    double doubleTest()
    {
        double a = 1000, b = 45, c = 12000, d = 2, e = 7, f = 1024;
        double a_ = std::sin( a );
        double b_ = std::asin( b );
        double c_ = std::sqrt( c );
        double d_ = d + d - d + d;
        double e_ = e * e + e * e;
        double f_ = f / f / f / f / f;
    
        return a_ / b_ / c_ / d_ / e_ / f_;
    }
    
    float floatTest()
    {
        float a = 1000, b = 45, c = 12000, d = 2, e = 7, f = 1024;
        float a_ = std::sin( a );
        float b_ = std::asin( b );
        float c_ = std::sqrt( c );
        float d_ = d + d - d + d;
        float e_ = e * e + e * e;
        float f_ = f / f / f / f / f;
    
        return a_ / b_ / c_ / d_ / e_ / f_;
    }
    
    int main()
    {
        const int loops = 1000000;
    
        std::cout << "double: ";
        double d = 0;
        auto double_begin = std::chrono::high_resolution_clock::now();
        for ( int i = 0; i < loops; ++i )
        {
            d += doubleTest();
        }
        auto double_end = std::chrono::high_resolution_clock::now();
        std::cout << "\nloops: " << loops << "  time: " << std::chrono::duration_cast<std::chrono::microseconds>(double_end - double_begin).count() << " microseconds\nresult: " << d << std::endl;
    
        std::cout << "\nfloat: ";
        float f = 0;
        auto float_begin = std::chrono::high_resolution_clock::now();
        for ( int i = 0; i < loops; ++i )
        {
            f += floatTest();
        }
        auto float_end = std::chrono::high_resolution_clock::now();
        std::cout << "\nloops: " << loops << "  time: " << std::chrono::duration_cast<std::chrono::microseconds>(float_end - float_begin).count() << " microseconds\nresult: " << f << std::endl;
    
        return 0;
    }
    

    Allerdings variiert das Ergebnis auch sehr stark, was wohl daran liegen wird, dass das Betriebssystem nun einmal nicht immer alle Berechnungen am Stück erledigt.
    Nach einigen Versuchen:
    double: 6300µs-15400µs
    float: 7000µs-14900µs

    Ich würde hier also keine generelle Aussage treffen und von eigentlich keinem Unterschied sprechen.



  • @lemon03 sagte in float vs double:

    Gibts da ein Tool vor

    Ja, dein Compiler ist das Tool. Da gibts normalerweise eine Option, welche den ASM ausgibt.

    Ich wuerde erstmal erwarten das es immer etwa doppelt so schnell ist, weil es mit floats nur die halbe Speicherbandbreite braucht.



  • @unterfliege sagte in float vs double:
    ....

    Ich würde hier also keine generelle Aussage treffen und von eigentlich keinem Unterschied sprechen.

    Weil seit dem Intel Pentium Prozessor Fliesskommazahlen vom integrierten Fliesskommaprozessor in Hardware berechnet werden und den wird inzwischen jeder moderne Compiler benutzen.



  • Was würde man unter einem nicht-modernen Compiler verstehen?



  • Borland C++ 3.1 zB.



  • @swordfish sagte in float vs double:

    Borland C++ 3.1

    Aha. 1992? 😃

    Und man kann davon ausgehen, das solche Compiler noch regelmäßig genutzt werden? Weil sonst, verzeiht mir die Feststellung, alle bisherigen Antworten bis der von Burkhi obsolet wären?

    Ist float vs double also nur eine Stil-Frage?



  • @lemon03 sagte in float vs double:

    Ist float vs double also nur eine Stil-Frage?

    OMFG. Miss es!



  • Oh my fucking God?

    Ich werde das halt mit meinen eigenen Routinen testen, und wenn sich irgendein Unterschied auftut, werde ich mich entsprechend entscheiden. Und damit wird dieses Thema für mich ausreichend behandelt sein. Danke.



  • @lemon03 sagte in float vs double:

    Ich werde das halt mit meinen eigenen Routinen testen, und wenn sich irgendein Unterschied auftut, werde ich mich entsprechend entscheiden.

    👍



  • BTW: Man muss die Werte nicht unbedingt ausgeben. Wenn die Variable wo man das Ergebnis reinschiebt volatile ist reicht das. Schreiben von volatile Zeugs gilt als beobachtbar, auch wenn es in Wirklichkeit gar nicht beobachtbar ist. Also z.b. auch wenn die Variable lokal ist und der Scope der Variable direkt nach der Zuweisung endet. Compiler halten sich trotzdem daran.



  • @lemon03 sagte in float vs double:

    @swordfish sagte in float vs double:

    Borland C++ 3.1
    

    Aha. 1992? 😃

    Und man kann davon ausgehen, das solche Compiler noch regelmäßig genutzt werden? Weil sonst, verzeiht mir die Feststellung, alle bisherigen Antworten bis der von Burkhi obsolet wären?

    Ist float vs double also nur eine Stil-Frage?

    Eher wohl eine Frage der benötigten Genauigkeit.😉


Anmelden zum Antworten