(% 256)이 (a & 0xFF)와 다른 이유는 무엇입니까? load an example. int mod(int num) {

나는 항상 (a % 256)옵티 마이저를 할 때 내가 쓴 것처럼 효율적인 비트 단위 연산을 자연스럽게 사용할 것이라고 가정했습니다 (a & 0xFF).

컴파일러 탐색기 gcc-6.2 (-O3)에서 테스트 할 때 :

// Type your code here, or load an example.
int mod(int num) {
    return num % 256;
}

mod(int):
    mov     edx, edi
    sar     edx, 31
    shr     edx, 24
    lea     eax, [rdi+rdx]
    movzx   eax, al
    sub     eax, edx
    ret

그리고 다른 코드를 시도 할 때 :

// Type your code here, or load an example.
int mod(int num) {
    return num & 0xFF;
}

mod(int):
    movzx   eax, dil
    ret

내가 완전히 빠진 것 같습니다. 어떤 아이디어?



답변

이건 같은게 아니야. 를 시도 num = -79하면 두 작업에서 다른 결과를 얻을 수 있습니다. (-79) % 256 = -79, (-79) & 0xff양수입니다.

를 사용 unsigned int하면 작업이 동일하며 코드가 동일 할 것입니다.

PS- 누군가가 논평

그것들은 동일해서는 안되며로 a % b정의됩니다 a - b * floor (a / b).

그것이 C, C ++, Objective-C (즉, 질문의 코드가 컴파일되는 모든 언어)에서 정의되는 방식이 아닙니다.


답변

짧은 답변

-1 % 256수득 -1되지 255이다 -1 & 0xFF. 따라서 최적화가 올바르지 않습니다.

긴 대답

C ++에는 (a/b)*b + a%b == a꽤 자연스러운 규칙이 있습니다. a/b항상 소수 부분이없는 산술 결과를 반환합니다 (0쪽으로 잘림). 결과적으로 a%b부호와 같 a거나 0입니다.

분할 -1/256수율 0따라서이 -1%256있어야 -1상기 조건을 만족시키기 위해 ( (-1%256)*256 + -1%256 == -1). 이것은에서 분명히 다릅니다 -1&0xFF이다 0xFF. 따라서 컴파일러는 원하는 방식으로 최적화 할 수 없습니다.

N4606 상태 기준 C ++ 표준 [expr.mul §4] 의 관련 섹션 :

적분 피연산자의 경우, /연산자는 일부 분수 부분이 폐기 된 대수 몫을 산출합니다. 몫이 경우 a/b결과의 타입에서 표현할 수이고, (a/b)*b + a%b동일하다 a[…].

최적화 활성화

그러나 유형을 사용unsigned 하면 위의 규칙을 충족하는 최적화가 완전히 정확합니다 .

unsigned(-1)%256 == 0xFF

참조 .

다른 언어

이것은 Wikipedia에서 찾아 볼 수 있듯이 프로그래밍 언어에 따라 매우 다르게 처리 됩니다.


답변

C ++ 11부터는 음수 num % 256이면 양수가 아니 num어야합니다.

따라서 비트 패턴은 시스템에서 부호있는 유형의 구현에 따라 다릅니다. 음의 첫 번째 인수의 경우 결과는 최하위 8 비트의 추출이 아닙니다.

num귀하의 경우 에는 다른 문제가 될 것입니다 unsigned: 요즘 컴파일러가 인용하는 최적화를 거의 기대할 것 입니다.


답변

컴파일러의 추론에 대한 텔레파시 통찰력은 없지만 %음수 값 (및 반올림을 0으로 반올림)을 처리해야 &하지만 결과는 항상 8 비트보다 낮습니다.

sar부호 비트의 값으로 물러 비트를 채우고, “산술 오른쪽으로 이동”과 같은 나에게 명령 소리.


답변

수학적으로 말하면 모듈로는 다음과 같이 정의됩니다.

a % b = a-b * 바닥 (a / b)

바로 여기에 당신을 위해 그것을 정리해야합니다. 정수 나누기는 floor (a / b)와 동일하므로 정수의 바닥을 제거 할 수 있습니다. 그러나 컴파일러가 제안한대로 일반적인 트릭을 사용하려면 모든 a와 b에 대해 작동해야합니다. 불행히도, 이것은 사실이 아닙니다. 수학적으로 말하면, 당신의 트릭은 부호없는 정수에 대해 100 % 정확합니다 (답은 부호있는 정수가 깨져 있지만 -a % b가 양수이어야한다는 것을 확인하거나 거부 할 수 있습니다). 그러나 모든 b에 대해이 트릭을 수행 할 수 있습니까? 아마 아닙니다. 이것이 컴파일러가하지 않는 이유입니다. 결국, 모듈로가 하나의 비트 연산으로 쉽게 쓰여졌다면, 우리는 추가와 다른 연산과 같은 모듈로 회로를 추가 할 것입니다.