추이 내 대답에 :정수 나누기 7
Is this expression correct in C preprocessor
여기 내 장점 중 조금 해요, 나는 방법이 특정 최적화 작품을 이해하려고 노력 중이 야.
이 질문에 대해 언급 한 바와 같이, GCC는 7에 의해 정수 나누기를 최적화 :로 C로 다시 변환
mov edx, -1840700269
mov eax, edi
imul edx
lea eax, [rdx+rdi]
sar eax, 2
sar edi, 31
sub eax, edi
:
int32_t divideBySeven(int32_t num) {
int32_t temp = ((int64_t)num * -015555555555) >> 32;
temp = (temp + num) >> 2;
return (temp - (num >> 31));
}
이의 첫 번째 부분을 살펴 보자 :
를int32_t temp = ((int64_t)num * -015555555555) >> 32;
왜이 번호입니까?
음, 2^64를 7로 나누고 튀어 나오는 것을보십시오.
2^64/7 = 2635249153387078802.28571428571428571429
마치 엉망으로 보입니다. 8 진수로 변환하면 어떻게 될까요?
0222222222222222222222.22222222222222222222222
그건 아주 우연한 일치 패턴이 아닙니다. 우연의 일치는 아닙니다. 저는 우리가 7이 0b111
이라는 것을 기억하고 우리가 99로 나눌 때 10 진수로 반복되는 패턴을 얻는 경향이 있다는 것을 알고 있습니다. 따라서 7으로 나눌 때 8 진수로 반복되는 패턴을 얻을 수 있습니다.
번호가 어디서 들어 왔습니까?
(int32_t)-1840700269
는 (uint_32t)2454267027
* 7 = 17179869189
과 동일하며 마지막 17179869184 17179869189 7은 2^34의 배수에 가장 가까운 것을 의미 2^34
이다. 아니면 다른 방법 2454267027 7 곱하면이 숫자는 8 진수 무엇 2
의 전력에 매우 가까운 uint32_t
에 맞는 가장 큰 숫자가 넣어?
0222222222223
왜 이것이 중요한가요? 음, 우리는 7로 나누고 싶습니다.이 숫자는 2^34/7 ... 대략입니다. 그래서 우리가 곱한 다음 34 번 왼쪽으로 시프트하면 정확한 숫자에 아주 가까운 숫자를 얻어야합니다.
마지막 두 줄은 근사 오차를 패치하도록 설계된 것처럼 보입니다.
아마이 분야에 대한 지식 및/또는 전문 지식이 조금있는 사람이이 문제를 확인할 수 있습니다.
>>> magic = 2454267027
>>> def div7(a):
... if (int(magic * a >> 34) != a // 7):
... return 0
... return 1
...
>>> for a in xrange(2**31, 2**32):
... if (not div7(a)):
... print "%s fails" % a
...
실패는 근사 나를 넘어 비트가 실패하는 이유 분류 충분히 재미있게 0b11001100110011001100110011010001
입니다 3,435,973,841에서 시작하고, 패치를 고쳐 이유도있다.누가 여기에 내려 놓은 것 이상으로 마법이 작동하는지 어떻게 알 수 있습니까?
http://www.hackersdelight.org/divcMore.pdf –
해당 PDF는 마지막 줄이 무엇인지 결정하는 데 매우 도움이됩니다 (사인을 수정 함). 그러나, 내가 그것을 놓치지 않았다면 특히,이 알고리즘을 논의하는 것 같지 않았다. – OmnipotentEntity
최종 참조는 [여기] (http://gmplib.org/~tege/divcnst-pldi94.pdf) (gcc 컴파일러에서 구현) 및 후속 조치 [here] (http://gmplib.org/~tege/division-paper.pdf)를 참조하십시오. 구현은 [GMP] (http://gmplib.org/) 라이브러리에서 찾을 수 있습니다. ('gmp-impl.h'의'udiv_qrnnd_preinv') –