仅使用以下符号:
! ~ & ^ | + << >>
不使用循环
我需要确定32位整数的符号,并且需要返回1表示正数,0表示0和-1表示负数。
有什么想法吗?我最初考虑将31个位移,然后查看该符号,但显然这种方法行不通,现在我有点卡住了。
仅使用以下符号:
! ~ & ^ | + << >>
不使用循环
我需要确定32位整数的符号,并且需要返回1表示正数,0表示0和-1表示负数。
有什么想法吗?我最初考虑将31个位移,然后查看该符号,但显然这种方法行不通,现在我有点卡住了。
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
v
)以测试算法。 - jweyrich试试这个:
(x >> 31) | (((0 - x) >> 31) & 1)
(x >> 31) | (((~x + 1) >> 31) & 1)
编辑2:
针对评论中提出的问题(或者更确切地说是挑剔)...
这些解决方案需要满足以下假设条件才能有效:
0
与x相同类型。>>
当左操作数为负数时的特定行为? - Oliver Charlesworthx
,x>>31
的结果在实现中是有定义的,不能保证它的值是什么。在符合C标准的实现中,所有负数x
的值可能为0
。但我认为这是问题的缺陷——我强烈怀疑(a)期望的答案使用了一个不可移植的>>
运算符,以及(b)实际提问的问题没有解决方案。所以不要点踩。 - Steve Jessop为什么需要使用位运算符来实现这个功能?
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);
}
(~((x >> 31) & 1) + 1) | (((~x + 1) >> 31) & 1)
(z >> 31) & 1
当输入为负数时,结果为1,其他情况下结果为0。
任何出现以下内容的地方:
(~z + 1)
(x>>31) | !!x
与Mystical的回答不同,这里没有未定义行为。
如果您还想支持将右移定义为算术移位的系统:
~!(x>>31)+1 | !!x
编辑:对不起,我在第二个版本中漏掉了一个!
。应该是:
~!!(x>>31)+1 | !!x
这个版本仍然依赖于实现是二进制补码并具有算术或逻辑右移的情况,即如果实现定义的行为完全不同,则可能会出现问题。但是,如果将类型更改为无符号类型,则所有实现定义的行为都消失了,结果取决于x
的“符号”(高位和零/非零状态),可以是-1U
、0U
或1U
。
-1 >> 1 == 0
,这就是为什么我认为无法在没有某些额外假设的情况下解决该问题的原因。当然,说明这些假设可能是作业的一部分。 - Steve Jessop0
没有给出正确的答案。 - Steve Jessop我不确定这是绝对理想的做法,但我认为它相当可移植,并且至少比你之前的方法要简单一些:
#define INT_BITS 32
int sign(int v) {
return (!!v) | -(int)((unsigned int)v >> (INT_BITS-1));
}
这个怎么样:
int getsign(int n)
{
return (!!n) + (~((n >> 30) & 2) + 1);
}
..对于32位有符号整数,只使用2的补码。
!!n
会在n
非零时返回1。
((n >> 30) & 2)
会在高位(符号位)设置时返回2。按位取反和+1将其2的补码计算出来,得到-2或0。
加法计算为负值时返回-1(1 + -2),零时返回0(0 + 0),正值时返回+1(1 + 0)。
Dimitri的想法可以简化为(!!x) - ((x >> 30) & 2)
再给出一个神秘的解决方案:
~!x & ((-((unsigned) x >> 31)) | !!x)
!
和+
都不是位运算符。 - Oliver Charlesworthif (!x) return 0;
这样的操作吗? - Tom Zych