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

Trying to prevent overflow when adding two longs

我试图在两种情况下防止溢出,一种是将 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 时,会发生溢出,但不会检测到溢出。我认为这很奇怪,因为代码看起来还不错。

有人可以帮助我吗?

顺便说一句,

"checked" 不是一个选项。

通过执行加法 value + adder(其中 returns 和 long),您在检查溢出 时导致了溢出

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

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

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

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

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

  1. 两大阳性valueadderreturn非阳性结果
  2. 两大valueadderreturn非负结果

因此您必须检查 both 条件以获取 both 边界,格式为:

  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

正如@Bradley 所说,您在检查溢出时遇到了溢出。但问题远不止于此。

先看这一行

if(value + adder > long.MaxValue)

这里,valueadder都是long,加起来就是long。但问题是 long 会自动滚动而不是抛出异常,所以如果你的值大于 long 的最大值,你只会随机得到一些其他 long 值。

现在应该清楚为什么您不想这样做,但在我们讨论正确的解决方案之前,让我们看看您的 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;
    }
}