仅使用:
! 〜& ^ | +<< >>
没有LOOPS
我需要确定一个32位整数的符号,如果是正则我需要返回1,如果是0则返回0,如果是负则需要返回-1。
有什么想法吗?我首先考虑转移31位,然后看着那个标志,但显然不会工作,现在我有点陷入困境。
答案 0 :(得分:5)
试试这个:
(x >> 31) | (((0 - x) >> 31) & 1)
这个怎么样:
(x >> 31) | (((~x + 1) >> 31) & 1)
编辑2:
回应评论中提出的问题(或更确切地说是挑剔)......
这些解决方案的假设是有效的:
0
与x。答案 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 类型,则所有实现定义的行为都将消失,结果为-1U
,0U
或1U
,具体取决于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)