C# De ce diviziunea este mai lentă decât înmulțirea?

În limbajele de programare și în special C# există 4 operații aritmetice care pot fi efectuate: adunare, scădere, înmulțire și împărțire.

Și din perspectivă externă, poate părea că toate sunt similare în ceea ce privește performanța, dar se dovedește că una dintre ele este mult mai lent în comparație cu celelalte 3.

Care dintre ele este mai lent, vă puteți întreba? Diviziune.

Conform această hârtie HP:

Diviziunea în virgulă mobilă și rădăcina pătrată durează mult mai mult decât adunarea și înmulțirea. Ultimele două sunt calculate direct, în timp ce primele sunt de obicei calculate cu un algoritm iterativ. Cea mai obișnuită abordare este să folosiți o iterație Newton-Raphson fără diviziune pentru a obține o aproximare a inversei numitorului (diviziunii) sau a rădăcinii pătrate reciproce, apoi înmulțiți cu numărătorul (diviziunea) sau cu argumentul de intrare (rădăcină pătrată).

Pentru a verifica afirmația de mai sus, am decis să rulez un test simplu folosind codul de mai jos:

        //Generate two random numbers
        var rand = new System.Random();
        float a = rand.Next();
        float b = rand.Next();

        Debug.Log("Number a: " + a + " Number b: " + b);

        System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();

        watch.Start();
        //Addition
        for (int i = 1; i < 1000000; i++)
        {
            float tmp = a + b;
        }
        watch.Stop();
        //Output
        Debug.Log("Addition took: " + watch.Elapsed.TotalSeconds.ToString("0.0000") + " seconds");

        watch.Reset();
        watch.Start();
        //Subtraction
        for (int i = 1; i < 1000000; i++)
        {
            float tmp = a - b;
        }
        watch.Stop();
        //Output
        Debug.Log("Subtraction took: " + watch.Elapsed.TotalSeconds.ToString("0.0000") + " seconds");

        watch.Reset();
        watch.Start();
        //Multiplication
        for (int i = 1; i < 1000000; i++)
        {
            float tmp = a * b;
        }
        watch.Stop();
        //Output
        Debug.Log("Multiplication took: " + watch.Elapsed.TotalSeconds.ToString("0.0000") + " seconds");

        watch.Reset();
        watch.Start();
        //Division
        for (int i = 1; i < 1000000; i++)
        {
            float tmp = a / b;
        }
        watch.Stop();
        //Division
        Debug.Log("Division took: " + watch.Elapsed.TotalSeconds.ToString("0.0000") + " seconds");

Practic, am rulat un milion de adunări, scăderi, înmulțiri și împărțiri pentru cele două numere aleatoare și am măsurat timpul necesar pentru procesare a fiecăruia dintre ele, testul a fost repetat de 5 ori și iată rezultatul:

  • Adăugarea a durat în medie 0,0004 secunde
  • Scăderea a durat în medie 0,0003 secunde
  • Înmulțirea a durat în medie 0,0003 secunde
  • Diviziunea a durat în medie 0,0044 secunde

Rezultatul a arătat că adunarea, scăderea și înmulțirea sunt similare în ceea ce privește performanța, dar diviziunea pare să fie cu aproximativ 1100% mai lentă.

Nu este o diferență mică, ceea ce duce la concluzia că întotdeauna este mai bine să folosiți înmulțirea în loc de împărțire ori de câte ori este posibil. De exemplu, atunci când trebuie să împărțiți numărul la 2, cel mai bine este să îl înmulțiți cu 0,5.