[英]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: 这些解决方案的假设是有效的:
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
. 但是,如果将类型更改为无符号类型,则所有实现定义的行为都将消失,结果为
-1U
, 0U
或1U
具体取决于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.