我可以使用无符号右移来防止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)是另一种选择。

请参阅文档中未选中的关键字。