c中负数逻辑右移的实现
Implementation of logical right shift of negative numbers in c
有没有一种简单的方法可以在 c 中对负数进行逻辑右移,就像我们使用 >> 进行算术右移一样?
右移负数调用 C 中实现定义的行为。标准未指定会发生什么,但留给编译器指定。所以它可能导致算术移位,或者逻辑移位,或者可能完全是其他东西(比如旋转,虽然我从未听说过)。除非阅读特定的编译器文档,否则您无法知道或假设哪种方法适用于您的编译器。
无符号数总是使用逻辑移位。所以如果你想对一个负数进行逻辑移位,那么在移位之前转换为无符号:
int32_t i = -1;
i = (int32_t) ((uint32_t)i >> n); // guaranteed to give logical shift
同理,如果要保证算术移位:
int32_t i = -1;
bool negative = i < 0;
if(negative)
{
i = -i;
}
i = (int32_t) ((uint32_t)i >> n);
if(negative)
{
i = -i;
}
逻辑右移是通过在移位前将 int
值转换为 unsigned
来完成的:
int lsr(int n, int shift) {
return (int)((unsigned)n >> shift);
}
算术右移不能直接使用 >>
运算符对 C 中的负值进行运算,因为它的效果是实现定义的。这是一个没有测试的简单替代方案,它复制 2s 补码架构上所有值的符号位:
int asr(int n, int shift) {
unsigned u = (unsigned)n;
return (int)((u >> shift) | ~(((u & (unsigned)INT_MIN) >> shift) - 1));
}
这是一个简单的测试程序:
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
int lsr(int n, int shift) {
return (int)((unsigned)n >> shift);
}
int asr(int n, int shift) {
unsigned u = (unsigned)n;
return (int)((u >> shift) | ~(((u & (unsigned)INT_MIN) >> shift) - 1));
}
int main(int argc, char *argv[]) {
int n = (argc < 2) ? -2 : strtol(argv[1], NULL, 0);
int shift = (argc < 3) ? 2 : strtol(argv[2], NULL, 0);
printf("%d >> %d = %d\n", n, shift, asr(n, shift));
printf("%d >>> %d = %d\n", n, shift, lsr(n, shift));
return 0;
}
有没有一种简单的方法可以在 c 中对负数进行逻辑右移,就像我们使用 >> 进行算术右移一样?
右移负数调用 C 中实现定义的行为。标准未指定会发生什么,但留给编译器指定。所以它可能导致算术移位,或者逻辑移位,或者可能完全是其他东西(比如旋转,虽然我从未听说过)。除非阅读特定的编译器文档,否则您无法知道或假设哪种方法适用于您的编译器。
无符号数总是使用逻辑移位。所以如果你想对一个负数进行逻辑移位,那么在移位之前转换为无符号:
int32_t i = -1;
i = (int32_t) ((uint32_t)i >> n); // guaranteed to give logical shift
同理,如果要保证算术移位:
int32_t i = -1;
bool negative = i < 0;
if(negative)
{
i = -i;
}
i = (int32_t) ((uint32_t)i >> n);
if(negative)
{
i = -i;
}
逻辑右移是通过在移位前将 int
值转换为 unsigned
来完成的:
int lsr(int n, int shift) {
return (int)((unsigned)n >> shift);
}
算术右移不能直接使用 >>
运算符对 C 中的负值进行运算,因为它的效果是实现定义的。这是一个没有测试的简单替代方案,它复制 2s 补码架构上所有值的符号位:
int asr(int n, int shift) {
unsigned u = (unsigned)n;
return (int)((u >> shift) | ~(((u & (unsigned)INT_MIN) >> shift) - 1));
}
这是一个简单的测试程序:
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
int lsr(int n, int shift) {
return (int)((unsigned)n >> shift);
}
int asr(int n, int shift) {
unsigned u = (unsigned)n;
return (int)((u >> shift) | ~(((u & (unsigned)INT_MIN) >> shift) - 1));
}
int main(int argc, char *argv[]) {
int n = (argc < 2) ? -2 : strtol(argv[1], NULL, 0);
int shift = (argc < 3) ? 2 : strtol(argv[2], NULL, 0);
printf("%d >> %d = %d\n", n, shift, asr(n, shift));
printf("%d >>> %d = %d\n", n, shift, lsr(n, shift));
return 0;
}