在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)
对于上述解决方案,提到了一些错误/限制。我想清楚地理解相同的内容。请详细说明以下几点-
signed
和unsigned
进行类型转换?答案 0 :(得分:2)
如果x
超出y
多于INT_MAX
或x
少于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
。如果为负,则结果是实现定义的。但是,在这一点上,我们可能不得不接受一些依赖于实现的行为。此位黑客的全部要点是解决某些硬件的性能问题,因此,希望它的全部动机取决于实现。