确定32位int的符号

Pet*_*ter 8 c logic bit-manipulation

仅使用:

!〜&^ | + << >>

没有LOOPS

我需要确定32位整数的符号,如果为正则需要返回1,如果为0则返回0,如果为负则返回-1.

有任何想法吗?我首先考虑转移31位,然后看着那个标志,但显然不会工作,现在我有点卡住了.

Mys*_*ial 5

试试这个:

(x >> 31) | (((0 - x) >> 31) & 1)
Run Code Online (Sandbox Code Playgroud)

这个怎么样:

(x >> 31) | (((~x + 1) >> 31) & 1)
Run Code Online (Sandbox Code Playgroud)

编辑2:

回应评论中提出的问题(或者说是挑选)

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

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

  • `-`不在允许的运算符列表中,不是吗? (7认同)
  • 这是错的."x >> 31"的结果是对负"x"的实现定义,不能保证它的值是什么.对于符合C的实现中的所有负"x",它可以是"0".但我认为这是问题中的缺陷 - 我强烈怀疑(a)预期答案使用不可移植的`>>,而(b)实际问的问题没有解决方案.所以没有downvote. (3认同)

jwe*_*ich 5

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

int sign = (v > 0) - (v < 0);
Run Code Online (Sandbox Code Playgroud)

不使用减法(假设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;
}
Run Code Online (Sandbox Code Playgroud)

结果如下:

$ gcc -o test test.c -Wall -Wextra -O3 -std=c99 && ./test && echo $#
passed zero test
passed all negative tests
passed all positive tests
0
Run Code Online (Sandbox Code Playgroud)