Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/64.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
大于C中的函数_C_Bitwise Operators - Fatal编程技术网

大于C中的函数

大于C中的函数,c,bitwise-operators,C,Bitwise Operators,我知道这是一个由来已久的问题,您可能也遇到过这个问题,但我的解决方案中有一个bug,我不知道如何解决它。我需要写一个比较两个整数的函数。我只允许使用操作(!、~、&、^、|、+、>>,,首先让我们澄清一下,我们假设: 负整数用2的补码表示 int正好是32位宽,long-long正好是64位宽 右移负数是一种算术移位 解决方案中的(~x+1)部分有问题,它应该返回-x。问题是INT\u MIN的绝对值大于INT\u MAX的绝对值,因此当x是INT\u MIN时,(~x+1)产生INT\u

我知道这是一个由来已久的问题,您可能也遇到过这个问题,但我的解决方案中有一个bug,我不知道如何解决它。我需要写一个比较两个整数的函数。我只允许使用操作(!、~、&、^、|、+、>>,,首先让我们澄清一下,我们假设:

  • 负整数用2的补码表示
  • int
    正好是32位宽,
    long-long
    正好是64位宽
  • 右移负数是一种算术移位
解决方案中的
(~x+1)
部分有问题,它应该返回
-x
。问题是
INT\u MIN
的绝对值大于
INT\u MAX
的绝对值,因此当x是
INT\u MIN
时,
(~x+1)
产生
INT\u MIN
而不是您所期望的
-INT\u MIN

解决方案的
y+(-x)
部分也存在溢出问题(第二步)

现在,如果允许您使用除
int
以外的其他类型,我们可以通过在转换之前将值强制转换为
long
来解决这两个问题,假设它是64位类型,这样
(~x+1)
将返回预期结果
-x
y+-x)
不会导致任何溢出。显然,我们必须将
>31
位更改为
>63

最终解决方案如下:

static bool isGreater(int x, int y)  {
    long long llx = x;
    long long lly = y;
    long long result = ((lly+(~llx+1))>>63)&1;
    return result;
}
用一些特殊情况测试它是可行的,例如
x==INT\u MIN
x==0
x==INT\u MAX

int main(void) {
    int x = INT_MIN;
    for (long long y = INT_MIN; y <= INT_MAX; ++y) {
        assert(isGreater(x, y) == (x > y));
    }
    x = INT_MAX;
    for (long long y = INT_MIN; y <= INT_MAX; ++y) {
        assert(isGreater(x, y) == (x > y));
    }
    x = 0;
    for (long long y = INT_MIN; y <= INT_MAX; ++y) {
        assert(isGreater(x, y) == (x > y));
    }
}
int main(无效){
int x=int_MIN;
对于(long long y=INT_MIN;y y));
}
x=INT_MAX;
对于(long long y=INT_MIN;y y));
}
x=0;
对于(long long y=INT_MIN;y y));
}
}
这在我的特定机器上使用特定的编译器是成功的。测试耗时163秒

但同样,这取决于是否能够使用除
int
以外的其他类型(但同样,通过更多的工作,您可以使用
int
模拟
long

如果您相应地使用
int32\u t
int64\u t
而不是
int
long
,那么整个程序可能更易于移植。但是,它仍然不是便携式的:

ISO/IEC 9899:2011§6.5.7位移位运算符

5 E1>>E2的结果是E1右移位E2位位置。如果E1具有无符号类型或E1具有有符号类型和非负值,则结果值为E1/2E2商的整数部分。如果E1具有有符号类型和负值,则结果值由实现定义


Hacker's Delight有一章比较谓词,这正是我们在这里需要的

它写的东西之一是:

x < y: (x - y) ^ ((x ^ y) & ((x - y) ^ x))
我有一个网站说它是有效的

如果允许使用局部变量,则可以通过分解子表达式将其简化一点
~(~y+x)


假设您知道
int
的大小,就会产生不可移植的代码。@JohnColeman试图通过按位操作获得
x>y
。我认为可以肯定的是,可移植性不是一个问题,我们假设32位和2位是互补的。我们现在不担心可移植性,因为这不是问题所在。@MarkWeston仍然存在右移是实现定义的问题,有些系统甚至可能没有定义
int32\t
。实际上,这个问题必须伴随着一系列特定于实现的条件。可移植性不是本练习的问题。这段代码永远不会接近生产代码。这只是位运算的练习。我同意资源可以更好地用于学习其他东西,而不是这些无用的技巧,但这就是OP发布的练习和问题。我甚至同意应该教授可移植性。但让我们把注意力集中在手头的问题上。
x < y: (x - y) ^ ((x ^ y) & ((x - y) ^ x))
// swap x <-> y
(y - x) ^ ((y ^ x) & ((y - x) ^ y))
// rewrite subtraction
~(~y + x) ^ ((y ^ x) & (~(~y + x) ^ y))
// get answer in lsb
((~(~y + x) ^ ((y ^ x) & (~(~y + x) ^ y))) >> 31) & 1
int diff = ~(~y + x);
return ((diff ^ ((y ^ x) & (diff ^ y))) >> 31) & 1;