2014-12-19 5 views
1

x64/sse에서 벡터 명령어를 사용하여 x % M을 계산하는 가장 빠르고/가장 빠른 방법은 무엇입니까? (%는 mod/나머지를 의미합니다.)SSE를 사용하여 모드/나머지를 계산하는 방법은 무엇입니까?

packed mod에 대한 opcode를 찾을 수 없으므로 float에 int를 승격시킨 다음 DIVPS 및 ROUNDPS를 사용하여 x - m * floor (x/m)를 계산하는 것이 가장 좋습니다.

내가 누락 된 더 나은 대안이 있습니까?

UPDATE : M에만 런타임에 알려져있다, 실제 루프는 다음과 같습니다

unsigned x[SIZE], M[SIZE], answer[SIZE]; 
for (int i = 0; i < SIZE; i++) { 
    answer[i] = x[i] % M[i]; 
} 

는 또한 M의 범위 1로 알려져있다 - 640,000,000, 그것은 어떤 식 으로든 도움이된다면.

+0

훨씬 빠르지 않습니다. 또한 한 번에 하나씩 반올림 오류가 있는지 확인해야 할 수도 있습니다. 분수 부분이 '0.5'에 매우 가까우면 계산 한 몫이 올바른 정수로 반올림되지 않을 수 있습니다. – Mysticial

+0

M이 2의 힘이 아니라면 나는 너에게 운이 없다고 생각한다. –

+1

'M'은 컴파일 타임 상수인가? –

답변

3

M이 컴파일 시간 상수이거나 루프 내에서 상수 인 경우 나눗셈을 사용하는 대신 calculated a reciprocal and then do multiplication and a shift을 사용할 수 있습니다. 우리는

x/M = (x*(2^n/M))>>n 

요인 2^n/M (일명 magic number가) 루프 전이나 컴파일시에 계산해야 쓸 수 있습니다. 예를 들어

우리는 x[i]/5 원한다면 우리는 x[i] 우리가 2^n/M = 0xCCCDn = 18을 사용할 수 있습니다 2^15보다 작은 것을 알고있다.

#include <stdio.h> 
#define N 32768 
int x[N], y[N], z[N]; 

int main(void) { 
    for(int i=0; i<N; i++) x[i] = i; 
    int M = 5; 
    int fact = 0xCCCD; 
    int n = 18; 
    for(int i=0; i<N; i++) { 
     y[i] = x[i]/M; 
     z[i] = (fact*x[i])>>n; 
     if(y[i] != z[i]) printf("%d %d\n", y[i], z[i]); 
    } 
} 

마법 번호를 결정하는 데는 여러 가지 방법이 있으며 n입니다. 나는 Agner Fog's Vector Class Library(VCL)을 사용합니다. 위의 코드에서 15 비트 숫자 대신 32 비트 숫자에 SSE2 또는 AVX2를 사용하는 경우이 작업을 수행합니다. 이 작업을 수행하는 어셈블리 코드를 보려면 assembly library도 SSE2 (및 아마도 AVX2)에 대해이 작업을 수행합니다.

자세한 내용은 VCL 설명서 22 페이지를 참조하십시오. 또한 그의 어셈블리 라이브러리 설명서에도 설명되어 있습니다.

+0

죄송합니다. M은 런타임에만 제공된다는 사실을 잊어 버렸습니다. 나는 그 질문을 갱신 할 것이다. 귀하의 답변을 주셔서 감사 드리며, 나는 Fog의 VCL을 알지 못했고 매우 유용하게 보입니다. – Ricbit

+2

@Ricbit'M'은 컴파일시의 상수 일 필요는 없습니다. 루프 내에서 상수 일 필요가 있습니다. 'fact'와'n'을 계산하는 데는 시간이 걸립니다. 반복을 할 때마다 그렇게해야한다면 분열을하는 것보다 느려질 것입니다. 그러나 루프 전에 계산하면 곱셈과 시프트를 사용하는 것이 훨씬 빠릅니다. –

+1

밝혀졌습니다. sse를 사용하지 않아도 mod를 두 곱셈으로 대체하여 이득을 얻었습니다. 아이디어에 다시 한번 감사드립니다. – Ricbit