简体   繁体   English

确定32位int的符号

[英]Determine the sign of a 32 bit int

Using ONLY: 仅使用:

! ~ & ^ | 〜&^ | + << >> + << >>

NO LOOPS 没有LOOPS

I need to determine the sign of a 32 bit integer and I need to return 1 if positive, 0 if 0 and -1 if negative. 我需要确定32位整数的符号,如果为正则需要返回1,如果为0则返回0,如果为负则返回-1。

Any ideas? 有任何想法吗? I first thought about shifting over 31 bits and then looking at that sign but that obviously wont work and now I am kind of stuck. 我首先考虑转移31位,然后看着那个标志,但显然不会工作,现在我有点卡住了。

Try this: 试试这个:

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

How about this: 这个怎么样:

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

EDIT 2: 编辑2:

In response to issues (or rather nit-picking) raised in the comments... 回应评论中提出的问题(或者说是挑选)

Assumptions for these solutions to be valid: 这些解决方案的假设是有效的:

  1. x is of type 32-bit signed integer. x是32位有符号整数类型。
  2. On this system, signed 32-bit integers are two's complement. 在这个系统上,带符号的32位整数是两个补码。 (right-shift is arithmetic) (右移算术)
  3. Wrap-around on arithmetic overflow. 算术溢出的环绕。
  4. For the first solution, the literal 0 is the same type as x. 对于第一个解决方案,文字0与x的类型相同。

If conditionals (not if statements) and subtraction are allowed, the simplest & cleaner solution (IMO) is: 如果条件表达式(不if语句)和减法是允许的,最简单和清晰的解决方案(IMO)是:

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

Not using subtraction (and assuming int is 32 bits): 不使用减法(假设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;
}

Here's are the results: 结果如下:

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

Why do you need to use bitwise operators for that? 为什么需要使用按位运算符?

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

If you absolutely have to use bitwise operators, then you can use the & operator to check for negative values, no shifting needed: 如果您必须使用按位运算符,则可以使用&运算符检查负值,无需转换:

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

If you want to shift: 如果你想转移:

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

A bit more convoluted, but there is this: 有点复杂,但有这样的:

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

This should take care of the ambiguity of whether the shift will fill in 1's or 0's 这应该考虑到班次是填写1还是0的模糊性

For a breakdown, any place we have this construct: 对于细分,我们有这个构造的任何地方:

(z >> 31) & 1

Will result in a 1 when negative, and a 0 otherwise. 当否定时将导致1,否则将导致0。

Any place we have: 我们有的地方:

(~z + 1)

We get the negated number (-z) 我们得到否定的数字(-z)

So the first half will produce a result of 0xFFFFFFFF (-1) iff x is negative, and the second half will produce 0x00000001 (1) iff x is positive. 因此,如果x为负,则前半部分将产生0xFFFFFFFF(-1)的结果,如果x为正,则后半部分将产生0x00000001(1)。 Bitwise or'ing them together will then produce a 0x00000000 (0) if neither is true. 如果两者都不为真,则按位或将它们组合在一起将产生0x00000000(0)。

I'm not sure this is the absolute ideal way to do things, but I think it's reasonably portable and at least somewhat simpler than what you had: 我不确定这是绝对理想的做事方式,但我认为这是合理的便携性,至少比你的方式简单:

#define INT_BITS 32

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

What about: 关于什么:

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

..for 32-bit signed int, 2's complement only. ..对于32位signed int,仅限2的补码。

!!n gives 1 if n is nonzero. !!n如果n非零,则!!n给出1。 ((n >> 30) & 2) gives 2 iff the high bit (sign) is set. ((n >> 30) & 2)如果设置了高位(符号)则给出2。 The bitwise NOT and +1 take the 2's complement of this, giving -2 or 0. Adding gives -1 (1 + -2) for negative values, 0 (0 + 0) for zero, and +1 (1 + 0) for positive values. 按位NOT和+1取2的补码,给出-2或0.对于负值,加法给出-1(1 + -2),对于零,给出0(0 + 0),+1(1 + 0)为正值。

Assuming the implementation defines arithmetic right shift: 假设实现定义了算术右移:

(x>>31) | !!x

Unlike Mystical's answer, there is no UB. 与Mystical的答案不同,没有UB。

And, if you want to also support systems where right shift is defined to be arithmetic shift: 并且,如果您还想支持将右移定义为算术移位的系统:

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

Edit: Sorry, I omitted a ! 编辑:对不起,我省略了! in the second version. 在第二个版本。 It should be: 它应该是:

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

This version is still dependent on the implementation being twos complement and having either arithmetic or logical right-shift, ie if the implementation-defined behavior were something else entirely it could break. 这个版本仍然是依赖于实现是二进制补码和具有或者算术逻辑右移,即如果实现定义的行为是别的东西完全可能打破。 However, if you change the types to unsigned types, all of the implementation-defined behavior vanishes and the result is -1U , 0U , or 1U depending on the "sign" (high bit and zero/nonzero status) of x . 但是,如果将类型更改为无符号类型,则所有实现定义的行为都将消失,结果为-1U0U1U具体取决于x的“符号”(高位和零/非零状态)。

Dimitri's idea could be simplified to (!!x) - ((x >> 30) & 2) 迪米特里的想法可以简化为(!! x) - ((x >> 30)&2)

And just to give one more cryptic solution: 而且只是提出一个更神秘的解决方案:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM