Zastępowanie dzielenia mnożeniem

0

Z tego co wiem dzielenie jest jedną z najbardziej kosztownych operacji arytmetycznych
Czy ma sens zastąpienie np linijki kodu:

cm = inch / 2.54;

taką:

cm = inch * 0.03937008;

? Załóżmy że to krytyczna linijka kodu która jest odpalana wielokrotnie

0

Oczywiście napisać kilkulinijkowy test nie jesteś w stanie?

0

Chodzi mi o ogólną zasadę - podejrzewam że w zależności od języka i kompilatora uzyskam różne rezultaty
Nie będę pisał testu dla każdego języka bo może ktoś ma doświadczenie którym może się podzielić

0

Kompilator sam powinien zamienić dzielenie przez stałą mnożeniem przez stałą.

0
Wibowit napisał(a):

Kompilator sam powinien zamienić dzielenie przez stałą mnożeniem przez stałą.

Tylko że - dwa warunki:

  1. Przyzwoity kompilator
  2. Pozwolono mu na to
0

Tak na szybko

static void Main(string[] args)
        {
            Stopwatch stopwatch = new Stopwatch();
            
            long[] timesM = new long[1000];
            stopwatch.Start();
            for (int j = 0; j < 1000; j++)
            {
                stopwatch.Restart();
                
                for (int i = 0; i < 10000; i++)
                {
                    double cm = i * 0.03937008;
                }
                timesM[j] = stopwatch.ElapsedTicks;

            }
            stopwatch.Stop();
            Console.WriteLine("Mnożenie: {0}", timesM.Average());


            long[] timesD = new long[1000];
            stopwatch.Start();
            for (int j = 0; j < 1000; j++)
            {
                stopwatch.Restart();
                for (int i = 0; i < 10000; i++)
                {
                   double cm = i / 2.54;
                }
                timesD[j] = stopwatch.ElapsedTicks;

            }
            stopwatch.Stop();
            Console.WriteLine("Dzielenie: {0}", timesD.Average());
            Console.ReadKey();
        }

    }

Mnożenie: 93,744
Dzielenie: 224,814
Mnożenie: 113,048
Dzielenie: 220,776
Mnożenie: 109,215
Dzielenie: 217,341

Mnożenie jednak 2 razy szybsze.

0

znalazłem poradę że można zastąpić dzielenie mnożeniem przez dzielenie, np:

x / 2.54

można zastąpić:

x * (1 / 2.54)

w ten sposób nie traci się tak dużo na czytelności, a kompilator dzielenie stałej przez stałą wyliczy w locie (w większości przypadków)

0

Ale stracisz na dokładności jak trafi ci sie binarny ułamek okresowy. Ja bym takie cuda zostawił kompilatorowi do rozstrzygania ;]

1
#include <iostream>
using namespace std;
 
volatile double x=120;

int main()
  {
   if(x*(1/10.0)!=x/10.0) cout<<"nie jest to dobry sposób"<<endl;
   return 0;
  }

http://ideone.com/HkmKK4

0

Skąd się bierze te dziwne zachowanie na tym kompilatorze? Na msvc obie wartości są równe i warunek nie zostaje spełniony.

0

Czemu dziwne? Założę się że standard nie mówi nic o tym, czy w tym przypadku ma być równość czy nie. Zależy to od tego jaki kod wypluje kompilator, czy też jak będzie zwijał stałe.

Gdyby zaimplementować kod w asemblerze tłumacząc wyrażenia wprost, to moim zdaniem powinna wyjść nierówność.

0

Nie rozumiem. Standard nie mówi o tym, że jeżeli oba wyrażenia mają taką samą wartość, to powinny być sobie równe?
Przerobiłem kod do takiej postaci: http://ideone.com/3zVr19 i wyszło, że obie zmienne, bajt po bajcie, są identyczne, ale jednocześnie nie są sobie równe. Jakim cudem?

0

Widocznie zwijanie stałych się gdzieś rozgałęziło i w jednej gałęzi zostało liczone inaczej niż w drugiej. Ciężko stwierdzić.

Jeśli przeszkodzi się trochę w zwijaniu stałych na etapie kompilacji (poprzez wrzucenie danych na wejście zamiast do kodu) to wynik jest bardziej zgodny z logicznym rozumowaniem: http://ideone.com/o13XWy

1

@Aux gcc -S prawdę ci powie ;)

0
Shalom napisał(a):

Ale stracisz na dokładności jak trafi ci sie binarny ułamek okresowy. Ja bym takie cuda zostawił kompilatorowi do rozstrzygania ;]

nie jest to dobry sposób

z pewnością zależy od zastosowania

osobiście potrzebuję użyć dzielenia dla każdego piksela w przychwytywanym obrazie z kamerki (czyli ponad kilkadziesiąt milionów razy na sekundę), precyzja jest rzeczą drugorzędną bo obraz z kamerki i tak jest zaszumiony

podejrzewam że w większości przypadków nie zależy nam na dokładności na 6 miejscu po przecinku, a jeśli zależy to i tak nie użyjemy liczb zmiennoprzecinkowych

tak samo można powiedzieć że magiczne 0x5f3759df to nie jest dobry sposób - a jednak dzięki temu gra potrafiła jak na tamte czasy cuda

0

Nie rozumiem. Standard nie mówi o tym, że jeżeli oba wyrażenia mają taką samą wartość, to powinny być sobie równe?

floating-point ma ograniczoną precyzję i nie trzyma się twierdzeń matematycznych w zakresie arytmetyki ;-)

Trzyma się pod warunkiem, że wszystkie = zastąpisz przez . Więc \frac x{10}\approx x\cdot\frac 1{10}\qquad x\in\begin{verbatim}double\end{verbatim}

To zwykle nie ma znaczenia, pod warunkiem że unikamy porównywań typu == z wyjątkiem ewentualnie porównania == 0.0 i == 1.0 dla uniknięcia dzielenia przez zero i przy logarytmach.

1 użytkowników online, w tym zalogowanych: 0, gości: 1