며칠 전, StackExchange 회원 Anto는 유효한 용도에 대해 문의했습니다. 비트 단위 연산자의 . 나는 정수에 2의 제곱을 곱하고 나누는 것보다 이동이 빠르다고 말했습니다. StackExchange 멤버 Daemin은 오른쪽 이동이 음수에 문제가 있다고 말하면서 반대했습니다.
그 시점에서 나는 부호있는 정수로 shift 연산자를 사용하는 것에 대해 생각하지 못했습니다. 주로이 기술을 저수준 소프트웨어 개발에 사용했습니다. 따라서 항상 부호없는 정수를 사용했습니다. C는 부호없는 정수에 대해 논리 이동을 수행합니다. 논리 시프트 권리를 수행 할 때는 부호 비트에주의를 기울이지 않습니다. 빈 비트는 0으로 채워집니다. 그러나 C는 부호있는 정수를 오른쪽으로 시프트 할 때 산술 시프트 연산을 수행합니다. 빈 비트는 부호 비트로 채워집니다. 이 차이로 인해 음수 값이 0으로 잘리는 대신 무한대로 반올림됩니다. 이는 부호있는 정수 나누기와는 다른 동작입니다.
몇 분의 생각으로 1 차 솔루션이 만들어졌습니다. 솔루션은 이동하기 전에 조건부로 음수 값을 양수 값으로 변환합니다. 시프트 연산이 수행 된 후 값이 조건부로 다시 음의 형태로 다시 변환됩니다.
int a = -5;
int n = 1;
int negative = q < 0;
a = negative ? -a : a;
a >>= n;
a = negative ? -a : a;
이 솔루션의 문제점은 조건부 할당 명령문이 일반적으로 하나 이상의 점프 명령으로 변환되며 점프 명령이 두 명령 경로를 모두 디코딩하지 않는 프로세서에서 비쌀 수 있다는 것입니다. 명령 파이프 라인을 두 번 다시 프라이밍해야하는 경우 분할을 넘어서서 얻을 수있는 성능 향상에 좋은 찌그러짐이 생깁니다.
위에서 말했듯이 토요일에는 조건부 할당 문제에 대한 답변으로 일어났습니다. 산술 시프트 연산을 수행 할 때 발생하는 반올림 문제는 2의 보수 표현으로 작업 할 때만 발생합니다. 보수 표현으로는 발생하지 않습니다. 이 문제에 대한 해결책은 시프트 연산을 수행하기 전에 2의 보수 값을 1의 보수 값으로 변환하는 것입니다. 그런 다음 1의 보수 값을 2의 보수 값으로 다시 변환해야합니다. 놀랍게도, 시프트 연산을 수행하기 전에 음의 값을 조건부로 변환하지 않고이 연산 세트를 수행 할 수 있습니다.
int a = -5;
int n = 1;
register int sign = (a >> INT_SIZE_MINUS_1) & 1
a = (a - sign) >> n + sign;
2의 보수 음수 값은 1을 빼서 1의 보수 음수 값으로 변환됩니다. 반대로, 1의 보수 음수 값은 1을 더하여 2의 보수 음수 값으로 변환됩니다. 위에 나열된 코드는 부호 비트가 2의 보수에서 1의 보수로 또는 그 반대로 변환하는 데 사용되기 때문에 작동합니다 . 음수 값만 부호 비트가 설정됩니다. 따라서 a 가 양수 이면 변수 부호 는 0과 같습니다 .
위에서 말한 것처럼 위의 것과 같은 다른 비트 해킹을 생각할 수 있습니까? 가장 좋아하는 비트 단위 핵은 무엇입니까? 저는 항상 새로운 성능 지향 비트 단위 핵을 찾고 있습니다.