【问题标题】:Check for arithmetic overflow and get overflow count?检查算术溢出并获取溢出计数?
【发布时间】:2014-03-24 14:35:51
【问题描述】:

检测算术溢出(或下溢)并获取溢出计数的最合适方法是什么?

为了更容易理解,我将使用byte,但这对于int 或任何其他基本整数类型都是相同的。现在想象一下我的值是 240 并且想给它加上 24。显然是算术溢出。使用checked 关键字至少很容易检测到...

byte value = 240;
try
{
    checked
    {
        value += 24;
    }
}
catch (OverflowException e)
{
    // handle overflow, get overflow count via % etc.
}

...通过抛出异常。

这是我目前正在使用的。

但是,我不太喜欢这个中的异常处理。异常通常非常昂贵,我想从一开始就避免它们。对我来说,这似乎是一个 Boneheaded-Exception 反正。 我可以做一些算术魔法来预先检测到这一点吗?

【问题讨论】:

    标签: c# exception math integer-overflow integer-arithmetic


    【解决方案1】:

    我猜你可以检查当前值和最大值之间的差异是否足够大以进行加法:

    var difference = byte.MaxValue - value;
    
    if(difference >= 24)//OK to add 24
    else//will cause overflow
    

    要检测下溢,您可以改用 byte.MinValue 值:

    var difference = value - byte.MinValue;
    if(difference >= 24)//OK to subtract 24
    else//will cause underflow
    

    考虑到这些,您可以为它们制作一些扩展方法:

    public static class OverflowExtensions
    {
        public static bool WillAdditionOverflow(this byte b, int val)
        {
            return byte.MaxValue - b < val;
        }
    
        public static bool WillSubtractionUnderflow(this byte b, int val)
        {
            return b - byte.MinValue < val;
        }
    }
    

    你可以这样使用:

    using MyApp.OverflowExtensions;
    //...
    
    if(value.WillAdditionOverflow(24))
        //value + 24 will cause overflow
    
    if(value.WillSubtractionUnderflow(24))
        //value - 24 will cause underflow
    

    【讨论】:

      【解决方案2】:

      反过来呢?

      byte oldValue = 240;
      byte newValue;
      
      unchecked
      {
        newValue = (byte)((oldValue + 24) % 255);
      }
      
      // if (newValue < oldValue), overflow happened and newValue 
      // contains the "amount" of overflow
      

      (字节需要% 255,因为byte + byte是一个整数,可能是出于便携性原因)

      请注意,这仅在您添加的数字与值的大小相同时才有效(即,两者都是字节,都是整数......)并且它仅适用于添加。对于减法,您只需反转比较 (newValue &gt; oldValue)。乘法时没有任何用处。

      这种方法的优点在于它不依赖于数据类型足够大而不会导致溢出,这是其他一些建议方法的弱点。

      【讨论】:

        【解决方案3】:

        这样的事情怎么样?

        if (byte.MaxValue - 240 < 24)
        {
            // handle overflow
        }
        

        对于下溢,比如说,看看你是否可以做 24 - 240

        if (byte.MinValue + 240 > 24)
        {
            // handle underflow
        }
        

        【讨论】:

        • 如果我弄错了,请纠正我,但这不会检测到下溢,或者是吗?
        • 对。您必须为下溢编写类似的检查。