2013-04-11 61 views
1

使用C#,我有几个自定义类,我需要能够检测整数溢出并返回默认的最小值或最大值,具体取决于溢出是否由于结果超过最大值或低于最小值。我似乎无法找到关于如何检测任何地方发生溢出的“类型”的建议。确定是否整数溢出超过或低于边界

这些类分为两种常用类型:使用有符号值的类和使用无符号值的类。

作为一个例子,这里是与Int32值交易的类别之一:

public class Stat32Tf : IStat32T<float> 
{ 
    #region fields 

    private int baseValue, baseAdjustment; 
    private float baseMultiplier; 

    #endregion 

    #region ctors 

    public Stat32Tf() 
    { 
     baseValue = 0; 
     baseAdjustment = 0; 
     baseMultiplier = 1f; 
    } 

    public Stat32Tf(int baseValue, int baseAdjustment = 0, float baseMultiplier = 1f) 
    { 
     this.baseValue = baseValue; 
     this.baseAdjustment = baseAdjustment; 
     this.baseMultiplier = baseMultiplier; 
    } 

    #endregion 

    #region properties 

    public int BaseValue 
    { 
     get 
     { 
      return baseValue; 
     } 
     set 
     { 
      baseValue = value; 
     } 
    } 

    public int BaseAdjustment 
    { 
     get 
     { 
      return baseAdjustment; 
     } 
     set 
     { 
      baseAdjustment = value; 
     } 
    } 

    public float BaseMultiplier 
    { 
     get 
     { 
      return BaseMultiplier; 
     } 
     set 
     { 
      baseMultiplier = value; 
     } 
    } 

    public int TruncValue 
    { 
     get 
     { 
      return (int)Value; 
     } 
    } 

    public float Value 
    { 
     get 
     { 
      return (baseValue + baseAdjustment) * baseMultiplier; 
     } 
    } 

    #endregion 

} 

正如你所看到的,阶级的思想是保持基本值,调整值,和乘数值,并返回Value属性中的聚合值。 (TruncValue属性就像它所暗示的那样,返回截断的整个值,并删除任何小数值)。

目标是处理Value属性的“get”访问器中的溢出,并且如果结果超过了max int值,则返回int.MaxValue,并且如果它低于最小值,则返回int.MinValue,所有这些都没有抛出实际的溢出错误。对我来说很棘手的部分是调整值和乘数也可能是负值(按照设计要求)。

什么是达到此目的的安全方法?我一直没有找到解决这种情况的资源。我猜测需要使用某种算术算法来确定结果是否超出或不足。

+0

如果发生溢出并且结果为肯定,那么溢出正在进行。如果结果为负数,则溢出会超过 – 2013-04-11 12:58:40

+0

@caerolus如果涉及到乘法,它并不是那么容易,结果仍可能具有预期的符号:32位(如果有符号,则为2的补码)的“123456 * 987654 = 1672727936”整数具有环绕溢出行为。 – 2013-04-11 13:01:33

+0

Just FYI,C#中的整数溢出默认情况下不会抛出OverflowException;只有在“检查”环境中。 – 2013-04-11 13:03:05

回答

0

漂浮很大。你是否期望获得值溢出或你期望转换为int溢出?如果这只是铸造类似于下面的代码可能工作。

//This answer is wrong, see below. 
public int TruncValue 
{ 
    get 
    { 
     if (Value > (float)int.MaxValue) 
     { 
      return int.MaxValue 
     } 
     else if (Value < (float)int.MinValue) 
     { 
      return int.MinValue 
     } 
     else 
     { 
      return (int)Value; 
     } 
    } 
} 

尽管您可能需要对边缘情况进行一些额外的处理。

编辑 - 我在一些代码中玩弄了这个,发现了一些我没有想到的行为,但显然它在规范中。

例如,

var Value = int.MaxValue + int.MaxValue //Ends up returning -2 with no exception in debug mode. 
var MaxCalculatedValue = (int.MaxValue + int.MaxValue) * float.MaxValue //Ends up returning something like -3.4... ^38. 

你真的可能需要多达投万事成一张双人床和然后检查如果结果比int大于或小于。

因此,它可能是这个样子:

public float Value 
{ 
    get 
    { 
     var result = ((double)baseValue + (double)baseAdjustment) * (double)baseMultiplier; 
     if (result > (double)int.MaxValue) 
     { 
      return (float)int.MaxValue) 
     } 
     if (result < (double)int.MinValue) 
     { 
      return (float)int.MinValue) 
     } 
     return (float)result; 
    } 
} 
+0

“目标是处理Value属性的”get“访问器中的溢出” – 2013-04-11 13:15:15

+0

是的,我担心溢出的int值,但浮点结果仍然需要在允许的int范围内。我会在Value prop中尝试这样的事情,看看它是否按预期工作。 – 2013-04-11 13:27:21

+1

已更新的答案。我假设行为没有经过测试,看起来让我陷入了麻烦。至少我学到了一些东西。 – cgotberg 2013-04-11 13:54:57

2

只有数量有限的情况下它可能会溢:

  • 如果baseValue和baseAdjustment都为负 - >如果诠释.MinValue - baseAdjustment> baseValue,那么你有一个下溢。

  • 如果baseValue + baseAjustment是负数且baseMultiplier是正数 - >如果引发了溢出异常,那么它只能是下溢。

  • 如果baseValue + baseAdjustment为正,但baseMultiplier为负 - >如果引发溢出异常,则它只能是下溢。

如果你想避免引发/捕获异常,那么它可能是一个比较复杂一点(你可能想投的结果,只要然后将其与Int.MaxValue;这样,它只会提高如果结果超过Long.MaxValue,则为异常)。

+0

这个问题提醒了我,我的代数技能已经有些褪色了。您的建议有助于阐明我的算法需要检查的内容。我们不想提出异常,但是我认为使用您给出的建议,我可能会想出一个算法来在应用之前检查操作数。 – 2013-04-11 13:33:54

+1

如果你想检查两个正数的乘法(比如说a和b)是否会溢出,你需要找出b的最大值:取Int.MaxValue和a之间的距离,将它除以a然后截断数字。如果b大于结果值,则会溢出。 – 2013-04-11 13:50:47

+0

检查后,我注意到您需要将1加到截断的数字中才能得到正确的值。 – 2013-04-11 14:11:02