关于位操作:检查两个整数是否具有相同符号的最简单方法?

关于位操作:检查两个整数是否具有相同符号的最简单方法?

Simplest way to check if two integers have same sign?

检查两个整数是否具有相同符号的最简单方法是什么?是否有任何简短的按位技巧可以做到这一点?


怎么了

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

?


这是一个在 C/C 中工作的版本,它不依赖于整数大小或存在溢出问题(即 x*y>=0 不起作用)

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

当然,你可以geek out和template:

1
2
3
4
5
template <typename valueType>
bool SameSign(typename valueType x, typename valueType y)
{
    return (x >= 0) ^ (y < 0);
}

注意:由于我们使用异或,所以我们希望在符号相同时 LHS 和 RHS 不同,因此对零进行不同的检查。


1
(a ^ b) >= 0

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


我会警惕任何确定整数符号的按位技巧,因为你必须假设这些数字在内部是如何表示的。

几乎 100% 的情况下,整数将作为二进制补码存储,但除非您使用的数据类型可以保证特定的存储格式,否则对系统内部进行假设并不是一个好习惯.

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

就个人而言,我只会使用您选择的语言的符号功能。这样的计算不太可能出现任何性能问题。


假设 32 位整数:

1
bool same = ((x ^ y) >> 31) != 1;

稍微简洁一点:

1
bool same = !((x ^ y) >> 31);

我不太确定我会认为"按位技巧"和"最简单"是同义词。我看到很多假设有符号 32 位整数的答案(尽管要求无符号整数会很愚蠢);我不确定它们是否会应用于浮点值。

"最简单"的检查似乎是比较两个值与 0 的比较;假设可以比较类型,这是非常通用的:

1
2
3
4
bool compare(T left, T right)
{
    return (left < 0) == (right < 0);
}

如果符号相反,你就错了。如果符号相同,则为真。


(integer1 * integer2) > 0

因为当两个整数共用一个符号时,相乘的结果总是正的。

如果您想将 0 视为同一个符号,也可以使其 >= 0。


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

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

在经过优化的现代处理器上,这可能只需要两条指令,不到 1ns。

不假设二进制补码算术:

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

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

使用乘法是个坏主意,因为它容易溢出。


如果 (x * y) > 0...

假设非零等。


作为技术说明,即使在现代架构上,位复杂的解决方案也将比乘法高效得多。你只节省了大约 3 个周期,但你知道他们怎么说"节省了一分钱"...


对于任何大小的 int 和补码运算:

1
2
3
#define SIGNBIT (~((unsigned int)-1 >> 1))
if ((x & SIGNBIT) == (y & SIGNBIT))
    // signs are the same

假设为 32 位

if(((x^y) & 0x80000000) == 0)

...由于溢出

,答案if(x*y>0)很糟糕


无分支C版:

1
2
3
int sameSign(int a, int b) {
    return ~(a^b) & (1<<(sizeof(int)*8-1));
}

整数类型的 C 模板:

1
2
3
template <typename T> T sameSign(T a, T b) {
    return ~(a^b) & (1<<(sizeof(T)*8-1));
}

就在我的头顶......

1
2
int mask = 1 << 31;
(a & mask) ^ (b & mask) < 0;

使用 std::signbit 的更好方法如下:

1
std::signbit(firstNumber) == std::signbit(secondNumber);

它还支持其他基本类型(doublefloatchar等)。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include<stdio.h>

int checksign(int a, int b)
{
 return (a ^ b);
}

void  main()
{
    int a=-1, b = 0;

    if(checksign(a,b)<0)
    {
        printf("Integers have the opposite sign");
    }
    else
    {
        printf("Integers have the same sign");
    }
}

回想我的大学时代,在大多数机器表示中,整数的最左边不是数字为负数时为 1,为正数时为 0 吗?

不过,我想这是相当依赖机器的。


if (a*b < 0) 符号不同,否则符号相同(或 a 或 b 为零)


int same_sign = !( (x >> 31) ^ (y >> 31) );

如果 (same_sign) ...
否则...


推荐阅读