2013-07-25 19 views
6

Jak pomnożyć dwa 64-bitowe liczby całkowite przez kolejne 2 64-bitowe liczby całkowite? Nie znalazłem instrukcji, które mogą to zrobić.SSE mnożenie z 2 64-bitowych liczb całkowitych

+0

Co oznacza "dwie liczby całkowite 64-bitowe" w tym kontekście? Masz na myśli parę 64-bitowych liczb całkowitych (a la liczb zespolonych) lub pojedynczą 128-bitową liczbę całkowitą reprezentowaną jako para liczb całkowitych 64-bitowych? –

+0

znaczy jeden m128i bitową liczbę całkowitą reprezentowane w postaci pary z 64 bitowych liczb –

+1

Możliwe duplikat [tej kwestii] (http://stackoverflow.com/questions/12200698/is-it-possible-to-use-sse-v2 -to-make-a-128-bit-wide-integer), a następnie. –

Odpowiedz

3

Trzeba by zaimplementować własną 64 bitową procedurę mnożenia za pomocą 32-bitowych operacji mnożyć. Prawdopodobnie nie będzie to bardziej efektywne niż wykonanie tego za pomocą kodu skalarnego, szczególnie, że będzie dużo tasowania wektorów, aby uzyskać wszystkie wymagane operacje.

+0

Z góry mojej głowy, nie było "pmuldqq" lub coś w SSE4 dodane? – hirschhornsalz

+0

Istnieje 'pmuldq' w SSE4 który jest 32x32 => 64 bit mnożyć, więc można używać, jako blok konstrukcyjny dla kawałka 64x64 mnożyć. –

+0

Czy znasz najlepszy algorytm skalarny (zakładając, że masz tylko sprzęt 32-bitowy)? Oto co bym zrobił. Chciałbym podzielić każdą liczbę na jej górną i dolną 32-bitową część, a następnie zrobić (a * b) = (al + ah) * (bl * bh) = t1 + t2 + t3 + t4, gdzie t1 = al * bl, t2 = al * bh, t3 = ah * bl t4 = ah * bh. Każdy termin będzie liczbą 64-bitową. Następnie t2 i t3 będzie musiał być podzielona na niskim i wysokim i ostateczna liczba to (a * b) L = T1 + T2L + t3l (a * b) h = t4 + T2H + T3H + c, gdzie c to dowolne przeniesienie z (a * b) l. To 4 mnożniki i 7 dodatków. Czy to gdzieś na SO? –

4

wiem, że to jest stare pytanie, ale ja rzeczywiście szukają dokładnie tego. Ponieważ wciąż nie ma instrukcji do tego, zaimplementowałem 64-bitowe mnożenie się z pmuldq jak wspomniał Paul R. To właśnie wymyśliłem:

__m128i Multiply64Bit(__m128i a, __m128i b) 
{ 
    auto ax0_ax1_ay0_ay1 = a; 
    auto bx0_bx1_by0_by1 = b; 

    // i means ignored 

    auto ax1_i_ay1_i = _mm_shuffle_epi32(ax0_ax1_ay0_ay1, _MM_SHUFFLE(3, 3, 1, 1)); 
    auto bx1_i_by1_i = _mm_shuffle_epi32(bx0_bx1_by0_by1, _MM_SHUFFLE(3, 3, 1, 1)); 

    auto ax0bx0_ay0by0 = _mm_mul_epi32(ax0_ax1_ay0_ay1, bx0_bx1_by0_by1); 
    auto ax0bx1_ay0by1 = _mm_mul_epi32(ax0_ax1_ay0_ay1, bx1_i_by1_i); 
    auto ax1bx0_ay1by0 = _mm_mul_epi32(ax1_i_ay1_i, bx0_bx1_by0_by1); 

    auto ax0bx1_ay0by1_32 = _mm_slli_epi64(ax0bx1_ay0by1, 32); 
    auto ax1bx0_ay1by0_32 = _mm_slli_epi64(ax1bx0_ay1by0, 32); 

    return _mm_add_epi64(ax0bx0_ay0by0, _mm_add_epi64(ax0bx1_ay0by1_32, ax1bx0_ay1by0_32)); 
} 
+2

Czy wykonałeś analizę porównawczą kodu w porównaniu z rejestrami ogólnego przeznaczenia? Byłbym zainteresowany wynikami, gdy robię tonę 64 razy na 64-bitowych mnożnikach. – jeteon

+0

Po prostu przeprowadziłem testy porównawcze, wciąż jest to szybsze niż mnożenie skalarne (skompilowane za pomocą cl/O2). Około 831600000 multiplikacji w śr. 0,37 sekundy na moim nieco potężnym i7 5820k. Tymczasem te same mnożenia skalarne wynosiły 1,71 na średnim. więc jest około 4 razy szybsze, co jest trochę dziwne. Wydaje mi się, że cl jest naprawdę dobry w optymalizowaniu superskalarnych instrukcji – JukesOnYou

Powiązane problemy