我可以使用无符号右移来防止C#中的整数溢出吗?
时间:2020-03-06 14:33:51 来源:igfitidea点击:
我希望为alwaysPositive分配一个正数,其中lareValue1和largeValue2的所有可能值(至少为1)。
以下语句导致缓冲区溢出:
int alwaysPositive = (largeValue1 + largeValue2) / 2;
我知道我可以通过减去和添加来防止它:
int alwaysPositive = largeValue1 + ((largeValue2 - largeValue1) / 2);
但是在其他编程语言中,我可以使用无符号位移位来解决问题:
int alwaysPositive3 = (largeValue1 + largeValue2) >>> 1;
如何在C#中做到这一点?
以下所有答案都可以解决问题。可能有很多方法可以做到这一点,但是它们(包括我的解决方案)都有一个共同点:它们看上去都被混淆了。
解决方案
我们可以使用uints:
uint alwaysPositive = (uint)(largeValue1 + largeValue2) / 2;
并不是说nitpick,而是意思是"整数溢出",而不是"缓冲区溢出"。
我不知道C#,所以可能还有另一种方法,但是我们可以通过掩盖最高位来模拟无符号移位:(x >> 1)&0x80000000
我们可以这样操作:
x = largeValue1; y = largeValue2; return (x&y)+((x^y)/2);
这是获取两个整数的平均值而不会发生溢出的一种令人费解的方法。
如果需要,可以将移位除以2,然后编译器仍然会为我们完成。
int alwaysPositive = (largeValue1 >> 1) + (largeValue2 >> 1) + (largeValue1 & largeValue2 & 0x01);
上面的想法是,如果在添加结果之前对结果进行预除法,则将避免溢出,因为两个高阶位都将被置位。然后,我们可以添加一些轻微的校正逻辑,以在两个都为正的情况下将值增加一(向下取整)。如果我们只关心其中一个是否为正(四舍五入),则可以将其更改为
int alwaysPositive = (largeValue1 >> 1) + (largeValue2 >> 1) + ((largeValue1 | largeValue2) & 0x01);
try { checked { alwaysPositive3 = (largeValue1 + largeValue2); } } catch (OverflowException ex) { // Corrective logic }
unchecked((largeValue1 + largeValue2)>> 1)是另一种选择。
请参阅文档中未选中的关键字。