添加两个long时尝试防止溢出

时间:2016-12-19 18:26:12

标签: c# unity3d overflow long-integer

我试图在两种情况下防止溢出,一种是将long与float相乘,另一种是在添加两个long时。

像:

public static long multiplyLong(long value, float multiplier)
{
    if (value * multiplier > long.MaxValue)
    {
        Debug.Log("greater then max value");
        return value = long.MaxValue;
    }
    else
    {
        Debug.Log("not greater then max value");
        return (long) (value * multiplier);
    }
}

public static long addLong(long value, long adder)
{
    if(value + adder > long.MaxValue)
    {
        Debug.Log("greater then max value");
        return value = long.MaxValue;
    }
    else
    {
        Debug.Log("not greater then max value");
        return value + adder;
    }
}

“multiplyLong”完美运行,而“addLong”不能正常工作。当使用addLong时,会有溢出,它不会检测到溢出。我认为这很奇怪,因为代码似乎没问题。

有人可以帮助我吗?

“已检查”不是btw的选项。

3 个答案:

答案 0 :(得分:3)

就像@Bradley说的那样,你的溢出检查会出现溢出。但问题比那更大。

让我们先看看这一行

if(value + adder > long.MaxValue)

此处,valueadder都是长片,将它们加在一起会导致很长时间。但问题是longs会自动翻转而不是抛出异常,所以如果你的值长时间大于最大值,你就会得到一些看似随意的其他长值。

现在应该清楚为什么你不想这样做但是在我们进入正确的解决方案之前,让我们看一下你的multiplyLong方法。具体来说,以下一行

if (value * multiplier > long.MaxValue)

在这个value是一个很长的,multiplier是一个浮点数,并将它们相乘得到一个浮点数,可以很容易地检查一下,这样你的支票似乎就可以了

但如果value * multiplier的值大于long.MaxValue并将其转换为long怎么办?

答案是你得到long.MinValue,肯定低于long.MaxValue

关于这个话题还有很多可以说的,但这应该足以让你相信你所做的事情并不好。

现在,你该怎么办?我建议使用decimal类型有两个原因。一,它的范围比long大得多(decimal可以达到79228162514264337593543950335,其中long只能达到9223372036854775807),另一个原因是当溢出发生时它抛出显式异常。

例如,这是我的代码重写版本

public static long multiplyLong(decimal value, decimal multiplier)
{
    try
    {
        return value*multiplier;
    }
    catch (OverflowException e)
    {
        Debug.Log("greater then max value");
        return decimal.MaxValue;
    }

}

public static long addLong(decimal value, decimal adder)
{
    try
    {
        return value+adder;
    }
    catch (OverflowException e)
    {
        Debug.Log("greater then max value");
        return decimal.MaxValue;
    }
}

答案 1 :(得分:2)

执行添加value + adder(返回long),导致检查溢出中的溢出

将结果强制为可以容纳更大数字的东西,即:

if(value + (Decimal)adder > long.MaxValue)

或者捕获Overflow异常,而不是提前检查溢出。您的乘法检查有效的原因是您的结果是float,可以容纳更大的数字。

请注意,您可以转换任一操作数,重点是您获得Decimal添加运算符而不是long运算符;与强制浮点除法的方式相同。

答案 2 :(得分:1)

您可以有两个可能的溢出情况:

  1. 两个 valueadder返回非正面结果
  2. 两个大否定 valueadder返回非否定结果
  3. 因此,您必须在表单中检查两个边框的两个条件:

      if ((value + adder < value && value + adder < adder) || 
          (value + adder > value && value + adder > adder)) {
        // Overflow
      }
    

    或者你可能想要把它放在

    public static long addLong(long value, long adder) {
      unchecked { // we'll detect overflow manually
        if (value + adder < value && value + adder < adder) {
          Debug.Log("greater then max value");
          return long.MaxValue;
        }
        else if (value + adder > value && value + adder > adder) {
          Debug.Log("less then min value");
          return long.MinValue;
        }
        else {
          Debug.Log("within the [min..max] range");
          return value + adder;
        }
      }
    }
    

    试验:

    addLong(2, 3);                   // within the [min..max] range
    addLong(long.MaxValue - 3, 5);   // greater then max value
    addLong(long.MinValue + 2, -5);  // less then min value