确定整数溢出是不是超过或低于界限

Posted

技术标签:

【中文标题】确定整数溢出是不是超过或低于界限【英文标题】:Determine if integer overflow is over or under bounds确定整数溢出是否超过或低于界限 【发布时间】:2013-04-11 12:52:30 【问题描述】:

使用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”访问器中的溢出,如果结果超过最大 int 值,则返回 int.MaxValue,如果低于最小值,则返回 int.MinValue,所有没有抛出实际的溢出错误。让我感到棘手的部分是调整值和乘数也可能是负值(根据设计要求)。

实现此目的的安全方法是什么?我还没有找到任何资源来解决这种情况。我猜需要使用某种算术算法来确定结果是否超过或低于。

【问题讨论】:

如果有溢出并且结果是肯定的,那么溢出就会发生。如果结果为负,则溢出结束 @caerolus 涉及乘法,这并不容易,结果仍然可以具有预期的符号:123456*987654 = 1672727936 用于具有环绕溢出行为的 32 位(如果有符号则为二进制补码)整数。 仅供参考,默认情况下,C# 中的整数溢出不会引发 OverflowException;仅在checked 环境中。 @DanielFischer 你说的很对,我指的只是添加。也许将整个事情计算为double,检查溢出然后再转换回float @John Willemse 是的,开发环境正在运行检查以进行调试,但为此它是微不足道的,因为我们实际上并不希望抛出溢出异常。我们只需要能够确定结果是否“会”溢出,然后确定溢出的方向,以便可以返回适当的默认值。 【参考方案1】:

只有少数情况下可能下溢:

如果 baseValue 和 baseAdjustment 都是负数 -> 如果 Int.MinValue - baseAdjustment > baseValue 则存在下溢。

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

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

如果您想避免引发/捕获异常,那么它可能会更复杂一些(您可能希望将结果转换为 long 并将其与 Int.MaxValue 进行比较;这样它只会在以下情况下引发异常结果超过 Long.MaxValue)。

【讨论】:

这个问题让我想起了我的代数能力有些退步了哈哈。您的建议有助于阐明我的算法需要检查的内容。我们不想引发异常,但我认为使用您提供的建议,我可能能够找到一种算法来在应用之前检查操作数。 如果你想检查两个正数(比如a和b)的乘法是否会溢出,你需要找出b的最大值:取Int.MaxValue之间的距离和a,将其除以a,然后截断数字。如果 b 大于结果值,那么它将溢出。 检查后发现需要将截断的数字加1才能得到正确的值。 我采用了接近上述解决方案的解决方案,因为它简化了问题,目前似乎没有强加任何错误或冲突,但我要感谢您的回答 Lam。如果我最终使用算术算法来解决这个问题,我肯定会根据你的回答来做。如果我可以在 *** 上选择正确的两个答案,我也想包括你的。【参考方案2】:

花车很大。您是期望 get 值溢出还是期望强制转换为 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.

您确实可能需要将所有内容都转换为 double,然后检查结果是大于还是小于 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;
    

【讨论】:

"目标是处理 Value 属性的 "get" 访问器中的溢出" 是的,这是我担心溢出的 int 值,但浮点结果仍然需要在允许的 int 范围内。我将在 Value 道具中尝试类似的方法,看看它是否按预期工作。 更新了答案。我在没有测试的情况下对行为做出了假设,看起来它给我带来了麻烦。至少我学到了一些东西。 我不得不稍微修改一下方法,但这与我采用的解决方案非常接近。我不需要将值向上转换为更大的数据类型,因为浮点类型为可能的最大值和最小值提供了足够的空间。但是,我必须创建一些常量值来表示强制转换的最小值和最大值。运行时值作为 max 和 mins 的性能是可怕的,但作为常数值,它的速度惊人地快。谢谢大家的帮助。

以上是关于确定整数溢出是不是超过或低于界限的主要内容,如果未能解决你的问题,请参考以下文章

数学与数字3:整数反转-溢出的统一处理法则

在 VBA 中睡觉(整数溢出!!)

数值溢出与精度损失

python不是用来处理整数溢出的吗?

python确定一个数是否完全平方数

LeetCode:颠倒整数