我正在完成一项家庭作业,我需要为最多24位运营商创建一个按位方法。我的代码有效...但我有25个操作员,一个太多了。有人能找到一种更有效的方法来做一段代码吗?
int isGreater(int x, int y)
{
int xSign = (x>>31);
int ySign = (y>>31);
int check1 = (xSign & ySign) | (~xSign & ~ySign);
int same = !((( x + ((~y) + 1) )>>31) & 0x1);
int check2 = (check1 & same) | (~check1 & !xSign);
int equal = ((!(x ^ y))<<31)>>31;
return 0 | (~equal & check2);
}
答案 0 :(得分:6)
尝试更改此行:
int check1 = (xSign & ySign) | (~xSign & ~ySign);
为此:
int check1 = (xSign & ySign) | ~(xSign | ySign);
这是一个较少的运营商。
答案 1 :(得分:4)
check1
仅仅是xnor
。你为什么不替换它:
int check1 = (xSign & ySign) | (~xSign & ~ySign);
用这个:
int check1 = ~(xSign ^ ySign);
你的版本有5个按位运算符,我的版本有2个。
请注意,如果您使用此代码,您的代码会更美观:
int check1 = !(xSign ^ ySign);
即逻辑否定而不是按位否定,但不要担心正确性,因为最后你无论如何都要取消所有高位。
答案 2 :(得分:2)
这一行:
return 0 | (~equal & check2);
可以简化为:
return (~equal & check2);
(带or
的按位0
没有任何效果)
答案 3 :(得分:2)
假设int
是32位宽,您可以替换它:
int equal = ((!(x ^ y))<<31)>>31;
用这个:
int equal = ((!(x ^ y)) & 0x1;
另拯救自己。
答案 4 :(得分:1)
由于你显然可以使用添加,在我看来有一个更简单的方法:
int isGreater(int x, int y) {
return ((unsigned)(~x + 1 + y)>>31) & 1;
}
基本思路非常简单 - 从y中减去x,并检查结果是否为负数。为了保持至少一点挑战,我假设我们不能直接进行减法,所以我们必须自己否定数字(使用二进制补码,所以翻转位并添加一个)。
五个操作员 - 如果你包括演员,则为六个。
值得注意的一点:你对same
的计算本身就足够了(实际上是过度的 - 你需要消除逻辑否定)。
进行快速测试[编辑:更新测试代码以包含更多边界条件]:
int main() {
std::cout << isGreater(1, 2) << "\n";
std::cout << isGreater(1, 1) << "\n";
std::cout << isGreater(2, 1) << "\n";
std::cout << isGreater(-10, -11) << "\n";
std::cout << isGreater(-128, 11) << "\n";
std::cout << isGreater(INT_MIN, INT_MIN) << "\n";
std::cout << isGreater(INT_MAX, INT_MAX) << "\n";
return 0;
}
0
0
1
1
0
0
0
0
......一切如预期。
答案 5 :(得分:1)
我在C中提出了这个相对较短的解决方案,它可以处理从INT_MIN
到INT_MAX
的所有整数。
它希望有符号整数实现为2的补码,并且它预计没有有符号溢出的副作用(已知会导致未定义的行为)。
#include <stdio.h>
#include <limits.h>
int isGreater(int x, int y)
{
// "x > y" is equivalent to "!(x <= y)",
// which is equivalent to "!(y >= x)",
// which is equivalent to "!(y - x >= 0)".
int nx = ~x + 1; // nx = -x (in 2's complement integer math)
int r = y + nx; // r = y - x (ultimately, we're interested in the sign of r,
// whether r is negative or not)
nx ^= nx & x; // nx contains correct sign of -x (correct for x=INT_MIN too)
// r has the wrong sign if there's been an overflow in r = y + nx.
// It (the r's sign) has to be inverted in that case.
// An overflow occurs when the addends (-x and y) have the same sign
// (both are negative or both are non-negative) and their sum's (r's) sign
// is the opposite of the addends' sign.
r ^= ~(nx ^ y) & (nx ^ r); // correcting the sign of r = y - x
r >>= (CHAR_BIT * sizeof(int) - 1); // shifting by a compile-time constant
return r & 1; // return the sign of y - x
}
int testDataSigned[] =
{
INT_MIN,
INT_MIN + 1,
-1,
0,
1,
INT_MAX - 1,
INT_MAX
};
int main(void)
{
int i, j;
for (j = 0; j < sizeof(testDataSigned)/sizeof(testDataSigned[0]); j++)
for (i = 0; i < sizeof(testDataSigned)/sizeof(testDataSigned[0]); i++)
printf("%d %s %d\n",
testDataSigned[j],
">\0<=" + 2*!isGreater(testDataSigned[j], testDataSigned[i]),
testDataSigned[i]);
return 0;
}
输出:
-2147483648 <= -2147483648
-2147483648 <= -2147483647
-2147483648 <= -1
-2147483648 <= 0
-2147483648 <= 1
-2147483648 <= 2147483646
-2147483648 <= 2147483647
-2147483647 > -2147483648
-2147483647 <= -2147483647
-2147483647 <= -1
-2147483647 <= 0
-2147483647 <= 1
-2147483647 <= 2147483646
-2147483647 <= 2147483647
-1 > -2147483648
-1 > -2147483647
-1 <= -1
-1 <= 0
-1 <= 1
-1 <= 2147483646
-1 <= 2147483647
0 > -2147483648
0 > -2147483647
0 > -1
0 <= 0
0 <= 1
0 <= 2147483646
0 <= 2147483647
1 > -2147483648
1 > -2147483647
1 > -1
1 > 0
1 <= 1
1 <= 2147483646
1 <= 2147483647
2147483646 > -2147483648
2147483646 > -2147483647
2147483646 > -1
2147483646 > 0
2147483646 > 1
2147483646 <= 2147483646
2147483646 <= 2147483647
2147483647 > -2147483648
2147483647 > -2147483647
2147483647 > -1
2147483647 > 0
2147483647 > 1
2147483647 > 2147483646
2147483647 <= 2147483647