检查两个整数是否具有相同符号的最简单方法是什么?

77

判断两个整数是否同号的最简单方法是什么?是否有一种简短的按位运算技巧可以实现此功能?

19个回答

245

有什么问题

return ((x<0) == (y<0));  

?


34
很遗憾我们都错过了简单的解决方案。嗯...什么也没有。 - Torlack
1
有关于带符号零和无符号零的问题,-0.0 和 0.0。 - Ólafur Waage
1
@Ólafur:OP指定了整数,而不是浮点数。 - Nicholas Knight
4
假设您希望将零视为与正整数具有相同的符号。 - SpoonMeiser
2
永远不要满足于一个被接受的答案!始终保持好奇心!也许是时候让SO重新考虑被接受答案的真正含义了。SO应该修改被接受答案的真正含义,以便最相关的答案浮现在顶部。否则,像我这样的大多数懒惰极客甚至都不会费心去寻找其他选择。 - taurus05
显示剩余2条评论

53

这里有一个在C/C++中运行的版本,它不依赖于整数大小也没有溢出问题(即x*y>=0不起作用)

bool SameSign(int x, int y)
{
    return (x >= 0) ^ (y < 0);
}

当然,你可以沉迷于技术并进行模板化:

template <typename valueType>
bool SameSign(typename valueType x, typename valueType y)
{
    return (x >= 0) ^ (y < 0);
}
注意:由于我们使用异或运算,当符号相同时,我们希望左操作数和右操作数不相同,因此需要对零进行不同的检查。

2
相当不错,我内心深处的C/C++黑客完全支持这段代码片段。而作为一名软件工程师,我质疑用户为什么需要以如此通用的方式了解这个。 - user7116
1
如果x=0且y>0,这个会失败吗? - Weckar E.

39
(a ^ b) >= 0

如果符号相同,则计算结果为1,否则为0。


哦,太好了! :-) 我很惊讶我错过了这个。这个解决方案真正好的地方在于它不依赖于底层整数表示中的特定位基数。 - Daniel Spiewak
1
这个程序在x86上产生了令人愉悦的紧凑形式“xorl %edi,%esi; sets %al”,仅6个字节和两条指令。它也是一个有趣的案例研究,因为它是一个具体的案例,其中返回'bool'而不是int会产生明显更好的代码。 - John Meacham
@JohnMeacham:想知道你所说的“在某些具体情况下,返回'bool'而不是'int'会产生明显更好的代码”是什么意思。 - MK.

12

对于任何位运算技巧来确定整数的符号,我会持谨慎态度,因为这会让你假设那些数字是如何在系统内部表示的。

几乎100%的情况下,整数将被存储为二进制补码格式,但是除非你使用了一种保证特定存储格式的数据类型,否则假设系统内部结构不是一个好习惯。

在二进制补码中,您可以仅检查整数中最后(最左)位以确定它是否为负数,因此您可以比较这两个位。这意味着0将与正数具有相同的符号,这与大多数语言中实现的符号函数不一致。

个人而言,我建议使用所选语言的符号函数。这样的计算不太可能导致任何性能问题。


1
C标准库提供了signbit()函数。也许很难通过自己设计的“位操作技巧”来击败优化器。 - user3850

6
假设使用32位整数:
bool same = ((x ^ y) >> 31) != 1;

略微更简洁:
bool same = !((x ^ y) >> 31);

3
那两个代码示例应该始终始终始终在前面加上代码注释(在现实生活中)。 - Jorge Córdoba
4
当然。在现实生活中,我可能会使用类似于 same = Math.Sign(x) == Math.Sign(y) 的东西。当人们要求这样的解决方案时,我通常会提供一些更加巧妙的解决方案。:D - Patrick
1
嗯,这不是有效的代码...你怎么指望 & >> 能工作呢? - MD XF
这不是我的本意。我完全不记得10年前在那个&符号上想了什么。 - Patrick

5

我不确定“位运算技巧”和“最简单”是否是同义词。我看到很多答案都假定了有符号的32位整数(虽然要求无符号可能有些愚蠢);我不确定它们是否适用于浮点数。

似乎“最简单”的检查方法是比较两个值与0的大小关系;这在类型可以进行比较的情况下是非常普通的:

bool compare(T left, T right)
{
    return (left < 0) == (right < 0);
}

如果符号相反,则得到false(假)。如果符号相同,则得到true(真)。

false && false == false 的结果是 false,但如果你想要得到正确的结果,需要将其转化为异或运算的否定形式。 - Daniel Spiewak

5

(integer1 * integer2) > 0

当两个整数同号时,它们的乘积总是正数。

如果您想无论如何都将0视为相同符号,则可以将其更改为 >= 0。


如果其中一个整数为0,那么你就有问题了。 - TatiOverflow
0既不是负数也不是正数,因此从技术上讲它不属于同一符号。 - Benjamin Autin

4

假设使用二进制补码算术(http://en.wikipedia.org/wiki/Two_complement):

inline bool same_sign(int x, int y) {
    return (x^y) >= 0;
}

这可以只需要两个指令,在优化后的现代处理器上不到1纳秒的时间。

不假设二进制补码算术:

inline bool same_sign(int x, int y) {
    return (x<0) == (y<0);
}

这可能需要额外的一到两个指令并且需要更长的时间。

使用乘法是一个不好的想法,因为它容易溢出。


3
如果 (x * y) > 0... 假设不为零等条件成立。

2
作为技术说明,位运算的解决方案在现代架构上比乘法更加高效。你只能节省大约3个时钟周期,但是你知道“省一分钱就是赚一分钱”的道理...

5
“存一分钱,九成九是万恶之源。” 这句话的意思是大部分时间人们贪小便宜会导致不良后果。 - ysth

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接