8

Patrząc na zestaw x86 produkowany przez kompilator, zauważyłem, że (bez podpisu) podziały liczby całkowitej są czasem implementowane jako multiplikacje całkowite. Te optymalizacji wydaje podążał za kształtemWykonaj podział całkowity za pomocą mnożenia

value/n => (value * ((0xFFFFFFFF/n) + 1))/0x100000000 

Na przykład, poprzez wykonywanie podziału 9:

12345678/9 = (12345678 * 0x1C71C71D)/0x100000000 

dzielenia przez 3 użyłby mnożenie 0x55555555 + 1, i tak dalej.

wykorzystując fakt, że dyspozycja mul przechowuje dużą część wyniku w rejestrze edx końcowy wynik podziału można uzyskać za pomocą jednego mnożenia z magicznej wartości. (Chociaż ta optymalizacja jest czasami używana w połączeniu z przesunięciem bitowym na końcu.)

Chciałbym dowiedzieć się, jak to działa. Kiedy to podejście jest prawidłowe? Dlaczego 1 należy dodać do naszej "magicznej liczby"?

+2

Stała, którą mnożymy przez jest przybliżeniem odwrotności. Przypadkowe +/- 1 tu i tam mają zapewnić, że jest to zawsze "zaokrąglone" poprawnie. Udowodnienie, że dana metoda jest prawidłowa, może być wykonane matematycznie lub przez brutalne badanie wszystkich liczników. (Dla wersji 32-bitowej jest to całkowicie wykonalne.) – Mysticial

+0

@Mysticial: To wygląda na odpowiedź. –

+0

@ScottHunter Może później, gdy nie będę pracować. Nie mam tutaj dość narzędzi, by udzielić wyczerpującej odpowiedzi. – Mysticial

Odpowiedz

10

Ta metoda nazywa się "Podział przez rozmnażanie niezmienne".

Stałe, które widzisz, są w przybliżeniu przybliżeniami odwrotności.

Więc zamiast computing:

N/D = Q 

zrobić coś takiego zamiast:

N * (1/D) = Q 

gdzie 1/D Jest to odwrotność które można precomputed.

Zasadniczo odwrotność jest nieprecyzyjna, chyba że D jest potęgą dwójki. Więc wystąpi jakiś błąd zaokrąglania. +1, który widzisz, jest poprawny w przypadku błędu zaokrąglania.


Najbardziej znanym przykładem jest przez podział 3:

N/3 = (N * 0xaaaaaaab) >> 33 

przypadku 0xaaaaaaab = 2^33/3 + 1.

To podejście zostanie uogólnione na inne dzielniki.

+1

Odwołaniem kanonicznym jest: T. Granlund i PL Montgomery," Podział przez niezmienne liczby całkowite za pomocą mnożenia ", w * Proceedings of the SIGPLAN '94 Conference on Programming Language Design i Implementacja *, 1994, str. 61-72. – njuffa

+1

Dodatkowe, bardziej aktualne odniesienie: N. Möller i T. Granlund, "Ulepszone dzielenie przez niezmienne liczby całkowite" * Transakcje IEEE na komputerach *, cz. 60, nie. 2, s. 165 -175, luty 2011. – njuffa

+0

Twoje uogólnienie i dowód są błędne. Również 0x55555556 dla dzielenia przez 3 działa tylko dla podpisanego zakresu, tj. do 2^31. – Jester