了解问题-不使用分支的最多两个数

时间:2018-07-29 15:59:56

标签: c bit-manipulation

this link,给出了找到两个最大数而不分支的问题的解决方案。

r = y + ((x - y) & ((x - y) >> (sizeof(int) * CHAR_BIT - 1))); // min(x, y)
r = x - ((x - y) & ((x - y) >> (sizeof(int) * CHAR_BIT - 1))); // max(x, y)

对于上述解决方案,提到了一些错误/限制。我想清楚地理解相同的内容。请详细说明以下几点-

  1. 在什么情况下会导致溢出?
  2. 为什么需要向signedunsigned进行类型转换?

1 个答案:

答案 0 :(得分:2)

如果x超出y多于INT_MAXx少于y多于INT_MIN,就会发生溢出。例如,如果INT_MAX为32767,x为32760,而y为−20,则x - y的数学值为32780,但大于32767 ,所以会发生溢出。

一个建议的解决方案是用x - y替换(unsigned) x - (unsigned) y,因为无符号算术以字长为模完成(例如16位unsigned的模数为65536)。因此,无符号算术产生的结果具有相同的位模式,就好像执行了两个补码符号算术一样没有溢出。

请注意,转移仍存在一些问题。 >> (sizeof(int) * CHAR_BIT - 1)的算术右移量比n中的位数少1,因此可以产生所有0位(对于正x-y)或所有1位(对于负x-y)。 int。但是,一旦我们转换为unsigned,则移位将是逻辑的(插入0位)而不是算术的(复制符号位)。而且,即使我们转换回带符号的int,C标准也不保证算术移位。

替代方法是:

r = x - ((unsigned) x - y & -(((unsigned) x - y) >> sizeof(int) * CHAR_BIT - 1));

此操作使用unsigned(产生0或1)执行移位,然后取反(产生所有0位或全部1位)。

然后将=右侧的整个表达式的结果转换为r的类型,即int。如果为负,则结果是实现定义的。但是,在这一点上,我们可能不得不接受一些依赖于实现的行为。此位黑客的全部要点是解决某些硬件的性能问题,因此,希望它的全部动机取决于实现。