Was ist am schnellste?



  • Hallo,

    Ich habe 4 Terme, die nur vom float t abhängen. Die sehen in etwa so aus:

    float term1 = 3*t*t*t + 2*t+t - t;
    float term2 = 6*t*t*t - 4*t*t*t ... usw.
    

    Ich habe also mehrmals ein t^3, t^4 und t^2. Meine Frage: Wird der Code schneller, wenn ich die Funktion pow() benutze? Die sollte ja gut optimiert sein, aber durch die ganzen Funktionsaufrufe wird der Vorteil ja vllt wieder zerstört?
    Oder wäre der Code schneller, wenn ich die t^3, t^4 einmal vorberechne und dann wiederverwende?
    Also sowas: float f1 = t*t*t;
    term1 = 3f1 + ...
    term2 = 5
    f1 + ...

    Was ist am schnellsten? Vorberechnung, pow() oder einfach die t*t*t lassen?



  • ➡ Horner-Schema


  • Mod

    Wenn du es genau wissen willst, dann benutz einen Profiler. Der Unterschied zwischen den verschiedenen Möglichkeiten hängt von zu vielen Faktoren ab, um eine allgemeingültige Antwort zu geben. Meine Vorhersage ist aber, dass (wenn dein Compiler auch nur irgendwas taugt) alles (fast) gleich schnell sein wird, denn die Werte werden einmal berechnet werden und danach immer wieder das alte Ergebnis benutzt werden.



  • Horner-Schema statt Profiler.



  • Oder wäre der Code schneller, wenn ich die t^3, t^4 einmal vorberechne und dann wiederverwende?

    Genau das.
    Wenn t konstant ist - sonst geht das ja wohl nicht.



  • Und wahrscheinlich noch schneller, wenn du höhere Potenzen aus tieferen berechnest. Also t^4 = (t2)2 und so weiter.



  • Wenns vorberechnet ist, denke ich, kann man auf sowas gut verzichten.
    Ein paar Nanosekunden bei der Initialisierung sparen... ich weiss nicht.



  • Danke für alle Tipps!

    Also t ist der einzige Parameter der Funktion, quasi: float foo(float t) { ... }

    Einer hat vorgeschlagen, dass ich es mit einem Profiler testen soll. Leider kenne ich mich da überhaupt nicht aus. Kann mir jemand einen guten und einsteigerfreundlichen Profiler für C++ (ich benutze Visual Studio 05, falls das ne Rolle spielt) empfehlen?

    Danke



  • schneller schrieb:

    Einer hat vorgeschlagen, dass ich es mit einem Profiler testen soll. Leider kenne ich mich da überhaupt nicht aus. Kann mir jemand einen guten und einsteigerfreundlichen Profiler für C++ (ich benutze Visual Studio 05, falls das ne Rolle spielt) empfehlen?

    Wenn du einen AMD-Prozessor hast, ist AMD CodeAnalyst sehr zu empfehlen. Allerdings sind solche Mikrooptimierungen nicht immer ganz einfach zu profilen, ich würde mich da eher auf grössere Bottlenecks konzentrieren. 😉



  • zeig mal den bisherigen code.



  • volkard schrieb:

    zeig mal den bisherigen code.

    So sieht der Code aus:

    D3DXVECTOR3 HermiteCurve::interpolate(float t) const { 
       assert(t>=0 && t<=1);
    
       float bf_1 = 2*t*t*t - 3*t*t + 1;  // blending function 1
       float bf_2 = -2*t*t*t + 3*t*t;
       float bf_3 = t*t*t - 2*t*t + t;
       float bf_4 = t*t*t - t*t;
       return bf_1 * p1 + bf_2 * p2 + bf_3 * r1 + bf_4 * r2;
    }
    

    Leider habe ich keinen AMD Prozessor, sondern einen Intel Core2Duo. Welchen Profiler nimmt man da am besten?



  • spantan würde mir so ein gefummel einfallen.

    D3DXVECTOR3 HermiteCurve::interpolate(float t) const { 
       assert(t>=0 && t<=1);
       float t2=t*t;
       float t3=t*t*t;
    
       float bf_4 = t3 - t2; // t3 - t2
       float tmp_1 = bf_4 - t2; // t3 - 2*t2
       float bf_3 = tmp_1 + t; // t3 - 2*t2 + t;
       float tmp_2 = tmp_1 + t3 - t2; // 2*t3 - 3*t2;
       float bf_2 = -tmp_2; // -2*t*t*t + 3*t*t;
       float bf_1 = tmp_2 + 1; // 2*t*t*t - 3*t*t + 1 // blending function 1
    
       return bf_1 * p1 + bf_2 * p2 + bf_3 * r1 + bf_4 * r2;
    }
    

    aber keine ahnung, ob das schneller oder langsamer ist.



  • schneller schrieb:

    Leider habe ich keinen AMD Prozessor, sondern einen Intel Core2Duo. Welchen Profiler nimmt man da am besten?

    Nur um Zeit zu messen, brauchst du keinen Profiler. Da reichen dir auch betriebssystemabhängige Funktionen. Leider kenne ich mich mit denen zu wenig aus, da ich bisher immer plattformunabhängige Implementierungen innerhalb von Bibliotheken (z.B. SFML) verwendet habe.

    Aber wie gesagt: Mikrooptimierungen sind nicht einfach zu profilen. Die Unterschiede zwischen den Messungen sind oft recht klein und können auch von vielen anderen Faktoren abhängen, zum Beispiel wie ausgelastet der Prozessor gerade ist. Wenn du ein wenig von Assembler verstehst, könntest du dir auch das kompilierte Programm anschauen.



  • darf man mal fragen wie du ohne profiles drauf gekommen bist, dass es genau die interpolate funktion viel zeit in deinem programm braucht?



  • amrande schrieb:

    darf man mal fragen wie du ohne profiles drauf gekommen bist, dass es genau die interpolate funktion viel zeit in deinem programm braucht?

    Seinen Ausgangspost habe ich jetzt eher als allgemeine Frage aufgefasst...



  • #include <iostream>
    #include <windows.h>
    
    using namespace std;
    
    int main() {
    LARGE_INTEGER start_ticks, ende_ticks, frequenz;
    
    double tick_diff     = 0;
    start_ticks.QuadPart = 0;
    ende_ticks.QuadPart  = 0;
    
    nochmal:
    
    cin.get();
    
    QueryPerformanceCounter(&start_ticks);
    QueryPerformanceFrequency(&frequenz);
    
    for (int i = 0; i < 80000000; ++i) {
    // ... hier deinen code testen ob er lahm oder schnell ist ...
    }
    
    // ... Ende der Geschwindigkeits-Tests!
    
    QueryPerformanceCounter(&ende_ticks);
    
    tick_diff = ((double) ende_ticks.QuadPart - (double) start_ticks.QuadPart) / frequenz.QuadPart;
    cout << tick_diff << endl;
    goto nochmal;
    

    hinweis: nur auf release testen. debug gibt ganz andere ergebnisse



  • nochmal: 
    // ...
    goto nochmal;
    

    Wieso das? Hier könnte man wirklich ohne Probleme eine Schleife verwenden.



  • Nexus schrieb:

    nochmal: 
    // ...
    goto nochmal;
    

    Wieso das? Hier könnte man wirklich ohne Probleme eine Schleife verwenden.

    Endlosschleife, ohne goto - sehr schön! 🤡



  • Alter Schwede schrieb:

    Endlosschleife, ohne goto - sehr schön! 🤡

    Normalerweise hat die Schleife eine Abbruchbedingung.

    Und ja, eine Endlosschleife ist immer noch besser als goto , da weiss man wenigstens, was passiert. Man hat einen separaten Block mit eigenem Gültigkeitsbereich und kann das Verhalten des Programms überblicken. Es gibt schon wenige berechtigte Anwendungsbereiche für goto , aber sicher nicht in Situationen, in denen eine Schleife nur Vorteile hat.



  • @Nexus
    goto gehoert zur Sprache - und es bereichert sie**.** 😉


Anmelden zum Antworten