Dlaczego podział float jest powolny?

Jakie są kroki algorytmu do dzielenia zmiennoprzecinkowego?

Dlaczego wynik jest wolniejszy niż powiedzmy, mnożenie?

Czy robi się to w ten sam sposób, w jaki działamy ręcznie? Przez wielokrotne dzielenie przez dzielnik, odejmowanie wyniku w celu uzyskania reszty, wyrównywanie liczby ponownie i kontynuowanie do reszty jest mniejsza niż określona wartość?

Również, dlaczego zyskujemy na wydajności, jeśli zamiast robić

a = b / c 

We do

d = 1 / c
a = b * d

?

Edytuj: W zasadzie pytałem, ponieważ ktoś poprosił mnie o rozdzielenie wartości między pretendentów w oparciu o przypisanie wag. Zrobiłem to wszystko w liczbach całkowitych, a później poproszono mnie o konwersję na float, co spowodowało spowolnienie wydajności. Interesowało mnie tylko, jak C lub c++ wykonują te operacje, które spowodowałyby powolność.

Author: Peter Mortensen, 2009-02-03

6 answers

Z hardwarowego punktu widzenia podział jest algorytmem iteracyjnym, a czas potrzebny jest proporcjonalny do liczby bitów. Najszybszy podział, który obecnie istnieje, wykorzystuje algorytm radix4, który generuje 4 bitowy wynik na iterację. Dla podziału 32-bitowego potrzebujesz co najmniej 8 kroków.

Mnożenie może być wykonywane równolegle do pewnego stopnia. Bez wchodzenia w szczegóły można podzielić duże mnożenie na kilka mniejszych, niezależnych. Te mnożenia można ponownie rozbić, dopóki nie osiągniesz poziomu bitowego lub zatrzymasz się wcześniej i użyjesz małej tabeli wyszukiwania w sprzęcie. To sprawia, że sprzęt mnożący jest ciężki z punktu widzenia nieruchomości krzemowych, ale również bardzo szybki. To klasyczna wymiana rozmiaru/prędkości.

Aby połączyć równoległe wyniki obliczeń, potrzebne są kroki log2, więc mnożenie 32 bitów wymaga 5 kroków logicznych (jeśli zejdziesz do minimum). Na szczęście te 5 kroków jest o wiele prostsze niż kroki podziału (to tylko dodatki). Oznacza to, że w praktyce mnożenie jest jeszcze szybsze.

 18
Author: Nils Pipenbrinck,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-03 11:07:03

Podział FPU często w zasadzie używa Newtona-Raphsona (lub innego algorytmu), aby uzyskać odwrotność, a następnie pomnożyć ją przez tę odwrotność. Dlatego operacja wzajemna jest nieco szybsza od operacji dywizji ogólnej.

Ten artykuł HP (który jest bardziej zrozumiały niż większość artykułów, na które się natknąłem, mówiących o Newtonie-Raphsonie) ma to do powiedzenia na temat podziału zmiennoprzecinkowego:

Dzielenie zmiennoprzecinkowe i kwadratowe korzeń trwa znacznie dłużej na Oblicz niż dodawanie i mnożenie. Dwa ostatnie to obliczane bezpośrednio, podczas gdy te pierwsze są zwykle obliczane z iteracją algorytm. Najczęstszym podejściem jest aby korzystać z wolnej od podziału Newton-Raphson iteracji, aby uzyskać przybliżenie do odwrotność mianownika (podział) lub plac wzajemny korzeń, a następnie pomnożyć przez licznik (podział) lub argument wejściowy (pierwiastek kwadratowy).

 21
Author: Michael Burr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-03 08:37:54

Jak opisano w artykule Wikipediialgorytm podziału, istnieją dwa główne aproces do podziału w komputerach:

Powolny Podział

Używa następującego powtarzania i znajduje jedną cyfrę na iterację: partialRemainder[j+1] = radix * partialRemainder[j] - quotientDigit[n-(j+1)]*denominator

Szybki Podział

Zaczyna się od estymacji i zbiega się na ilorazie. Dokładność zależy od liczby iteracji.

Podział Newtona-Raphsona (bardzo krótko):

  1. Oblicz oszacowanie wzajemne.
  2. Oblicz dokładniejsze szacunki wzajemności.
  3. Oblicz iloraz mnożąc dywidendę przez odwrotność.
 6
Author: John Mulder,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-06 18:35:54

Nie zyskasz wydajności robiąc

d = 1 / c
a = b * d

Prawdopodobnie masz na myśli:

d = 1 / c
a1 = b1 * d
a2 = b2 * d

W ten sposób podział odbywa się tylko raz.

Dzielenie jest Per se wolniejsze niż mnożenie, jednak nie znam szczegółów. Podstawowym powodem jest to, że podobnie jak funkcje takie jak sin lub sqrt, jest to matematycznie bardziej złożone. IIRC, mnożenie trwa około 10 cykli na przeciętnym procesorze, podczas gdy dzielenie trwa około 50 lub więcej.

Jak to się właściwie robi było ładnie wyjaśnione przez Johna Muldera.

 1
Author: mafu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-12 13:44:11

Pomyśl o sprzęcie, a zrozumiesz lepiej, dlaczego dzielenie zajmuje dużo więcej czasu niż mnożenie. Obie operacje są wykonywane na poziomie jednostek zmiennoprzecinkowych (FPU) i nawet w świecie integral ALUs, Obwód podziału jest dużo bardziej zajęty niż obwód mnożenia. Podejrzewałbym, że jest to tylko bardziej bolesne w świecie zmiennoprzecinkowym, ponieważ teraz dane nie są tylko najmniej znaczące uporządkowane cyframi, ale zamiast tego są uporządkowane przez IEEE 754 standard.

Jeśli chodzi o zaokrąglenie, to tak naprawdę chodzi o to, gdzie sygnały podróżujące między bramkami zostaną przylutowane do ziemi; tam, gdzie tak się dzieje, tracisz cyfry. Nie zaokrąglanie, tylko obcinanie.

A może pytałeś o symulowanie arytmetyki zmiennoprzecinkowej przy użyciu tylko liczb całkowitych?

 0
Author: Ed Carrel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-03 07:33:07

Podział zmiennoprzecinkowy nie jest dużo wolniejszy niż podział liczb całkowitych, ale kompilator może nie być w stanie wykonać tych samych optymalizacji.

Na przykład kompilator może zastąpić dzielenie liczb całkowitych między 3 mnożeniem i przesunięciem binarnym. Może również zastąpić dzielenie float pomiędzy 2.0 mnożeniem przez 0.5, ale nie może zastąpić dzielenia między 3.0 mnożeniem przez 1/3. 0, ponieważ 1/3. 0 nie może być dokładnie reprezentowane za pomocą liczb binarnych, dlatego błędy zaokrąglania mogą zmienić wynik podziału.
Ponieważ kompilator nie wie, jak wrażliwa jest Twoja aplikacja na błędy zaokrąglania (powiedzmy, że robisz symulację pogody, Zobacz Efekt motyla ), nie może wykonać optymalizacji.

 0
Author: ggf31416,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-03 12:38:00