C# Dlaczego dzielenie jest wolniejsze niż mnożenie?

W językach programowania, a konkretnie w C#, można wykonać 4 operacje arytmetyczne: dodawanie, odejmowanie, mnożenie i dzielenie.

Z zewnątrz może się wydawać, że wszystkie są podobne pod względem wydajności, ale okazuje się, że jeden z nich jest znacznie wolniejszy w porównaniu do pozostałych 3.

Który z nich jest wolniejszy, możesz zapytać? Podział.

Według tego papieru HP:

Dzielenie zmiennoprzecinkowe i pierwiastek kwadratowy zajmują znacznie więcej czasu niż dodawanie i mnożenie. Te dwa ostatnie są obliczane bezpośrednio, podczas gdy pierwsze są zwykle obliczane za pomocą algorytmu iteracyjnego. Najbardziej powszechnym podejściem jest użycie iteracji Newtona-Raphsona bez dzielenia w celu uzyskania przybliżenia odwrotności mianownika (dzielenie) lub odwrotności pierwiastka kwadratowego, a następnie pomnożenie przez licznik (dzielenie) lub argument wejściowy (pierwiastek kwadratowy)..

Aby zweryfikować powyższe stwierdzenie, zdecydowałem się przeprowadzić prosty test, korzystając z poniższego kodu:

        //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");

Zasadniczo przeprowadziłem milion dodawania, odejmowania, mnożenia i dzielenia dla dwóch losowych liczb i zmierzyłem czas potrzebny na przetworzenie każdej z nich. Test powtórzono 5 razy i oto wynik:

  • Dodawanie trwało średnio 0,0004 sekundy
  • Odejmowanie trwało średnio 0,0003 sekundy
  • Mnożenie trwało średnio 0,0003 sekundy
  • Dzielenie trwało średnio 0,0044 sekundy

Wynik pokazał, że dodawanie, odejmowanie i mnożenie są podobne pod względem wydajności, ale dzielenie wydaje się być około 1100% wolniejsze.

Niewielka różnica, która prowadzi do wniosku, że zawsze, gdy to możliwe, lepiej jest zastosować mnożenie zamiast dzielenia. Na przykład, jeśli chcesz podzielić liczbę przez 2, najlepiej pomnożyć ją przez 0,5.