确定32位int的符号

时间:2011-09-07 22:55:12

标签: c logic bit-manipulation

仅使用:

! 〜& ^ | +<< >>

没有LOOPS

我需要确定一个32位整数的符号,如果是正则我需要返回1,如果是0则返回0,如果是负则需要返回-1。

有什么想法吗?我首先考虑转移31位,然后看着那个标志,但显然不会工作,现在我有点陷入困境。

8 个答案:

答案 0 :(得分:5)

试试这个:

(x >> 31) | (((0 - x) >> 31) & 1)

这个怎么样:

(x >> 31) | (((~x + 1) >> 31) & 1)

编辑2:

回应评论中提出的问题(或更确切地说是挑剔)......

这些解决方案的假设是有效的:

  1. x是32位有符号整数类型。
  2. 在这个系统上,带符号的32位整数是二进制补码。 (右移是算术)
  3. 算术溢出包裹。
  4. 对于第一个解决方案,文字0与x。
  5. 的类型相同

答案 1 :(得分:5)

如果允许条件(不是if语句)和减法,最简单的&清洁解决方案(IMO)是:

int sign = (v > 0) - (v < 0);

不使用减法(假设int为32位):

#include <stdio.h>
#include <assert.h>
#include <limits.h>

int process(int v) {
    int is_negative = (unsigned int)v >> 31; // or sizeof(int) * CHAR_BIT - 1
    int is_zero = !v;
    int is_positive = !is_negative & !is_zero;
    int sign = (is_positive + ~is_negative) + 1;
    return sign;
}

int main() {
    assert(process(0) == 0);
    printf("passed the zero test\n");
    for (int v = INT_MIN; v < 0; v++) {
        assert(process(v) == -1);
    }
    printf("passed all negative tests\n");
    for (int v = 1; v < INT_MAX; v++) {
        assert(process(v) == +1);
    }
    printf("passed all positive tests\n");
    return 0;
}

以下是结果:

$ gcc -o test test.c -Wall -Wextra -O3 -std=c99 && ./test && echo $#
passed zero test
passed all negative tests
passed all positive tests
0

答案 2 :(得分:2)

为什么需要使用按位运算符?

int get_sign(int value)
{
    return (value < 0) ? -1 : (int)(value != 0);
}

如果您必须使用按位运算符,则可以使用&运算符检查负值,无需转换:

int get_sign(int value)
{
    return (value & 0x80000000) ? -1 : (int)(value != 0);
}

如果你想转移:

int get_sign(int value)
{
    return ((value >> 31) & 1) ? -1 : (int)(value != 0);
}

答案 3 :(得分:2)

有点复杂,但有这个:

(~((x >> 31) & 1) + 1) | (((~x + 1) >> 31) & 1)

这应该考虑到班次是填写1还是0的含糊不清

对于细分,我们有这个构造的任何地方:

(z >> 31) & 1

负数时会产生1,否则会产生0。

我们拥有的任何地方:

(~z + 1)

我们得到否定数字(-z)

因此,如果x为负,则前半部分将产生0xFFFFFFFF(-1)的结果,如果x为正,则后半部分将产生0x00000001(1)。如果两者都不成立,则按位或将它们组合在一起将产生0x00000000(0)。

答案 4 :(得分:1)

怎么样:

int getsign(int n)
{
  return (!!n) + (~((n >> 30) & 2) + 1);
}

..对于32位有符号int,仅为2的补码。

如果!!n非零,

n会给出1。 如果设置了高位(符号),则((n >> 30) & 2)给出2。按位NOT和+1取2的补码,得-2或0。 添加为负值提供-1(1 + -2),为零提供0(0 + 0),为正值提供+1(1 + 0)。

答案 5 :(得分:1)

假设实现定义算术右移:

(x>>31) | !!x

与Mystical的答案不同,没有UB。

并且,如果您还想支持将右移定义为算术移位的系统:

~!(x>>31)+1 | !!x

编辑抱歉,我在第二个版本中省略了!。它应该是:

~!!(x>>31)+1 | !!x

此版本仍然依赖于实现是二进制补码并且 算术逻辑右移,即如果实现定义的行为完全是其他的话可能会破裂。但是,如果将类型更改为 unsigned 类型,则所有实现定义的行为都将消失,结果为-1U0U1U,具体取决于x的“符号”(高位和零/非零状态)。

答案 6 :(得分:1)

我不确定这是一种绝对理想的做事方式,但我认为这是合理的便携性,至少比你的更简单:

#define INT_BITS 32

int sign(int v) { 
    return (!!v) | -(int)((unsigned int)v >> (INT_BITS-1));
}

答案 7 :(得分:0)

Dimitri的想法可以简化为(!! x) - ((x&gt;&gt; 30)&amp; 2)

只是提出一个更神秘的解决方案:

~!x & ((-((unsigned) x >> 31)) | !!x)