算术运算如何avoid/resolve溢出

How to avoid/resolve overflow in arithmetic operation

我刚开始接触 Unity 和 C#,尝试为计算器编写一个脚本,其中包含 2 个输入字段、必要算术运算的按钮和一个“结果”文本字段。所有基本功能都运行良好,但在弄乱 Power 的输入值时,我遇到了结果变量中值溢出的问题。谷歌搜索各种解决方案,我在下面的代码中解决了这个问题。问题是,提到的问题仍然存在,并且在测试应用程序时,我仍然在控制台中收到此错误:

OverflowException: Arithmetic operation resulted in an overflow. System.Decimal.op_Explicit (System.Single value) (at <695d1cc93cca45069c528c15c9fdd749>:0)

我认为 checked-关键字在我的代码中的实现方式可能不正确,但我无法弄清楚是什么方式。

我最初的想法是将结果值转换为 double 并为其设置上限,但据我所知,计算仍在进行,并且在我将值与阈值进行比较之前就发生了溢出,因此决定尝试其他方法工具。如果存在避免此错误的任何其他方法 - 那就太棒了。

public class Calculator : MonoBehaviour
{
    public Text Result;
    public InputField FirstNumber;
    public InputField SecondNumber;

    public void OnClickPower()
    {

        if (FirstNumber.text.ToString() != "" & SecondNumber.text.ToString() != "")
        {
            Debug.Log("Numbers Unequal > success");
            decimal i = decimal.MaxValue;
            int j;
            float k;

            j = int.Parse(FirstNumber.text);
            Debug.Log("First number > " + j);

            j = int.Parse(FirstNumber.text);
            Debug.Log("Second number > " + j);

            k = Mathf.Pow(float.Parse(FirstNumber.text), float.Parse(SecondNumber.text));
            Debug.Log("Result in float > " + k);
            decimal l = Convert.ToDecimal(k);
            Debug.Log("Result in decimal > " + l);

            try
            {
                l = checked(i + l);
                Result.text = l.ToString();
            }
            catch (OverflowException ex)
            {
                Debug.Log(ex);
                Result.text = l.ToString();
            }

        }
        else
        {
            Result.text = "NO NUMBERS";
        }
    }
};

如果您需要处理非常大的值,请使用 System.Math 而不是 Mathf,因为 double 支持比 float 更大的值。

至于检查结果是否会溢出,在确定它是否安全之前不要使用Pow。回想一下代数。你可以检查Math.Log(Double.MaxValue, base),如果结果小于exponent那么你可以知道Math.Pow(base, exponent)会大于最大值,这意味着它会溢出。

例如:

// Avoid shadowing Unity's Random if you're using it.
using Math = System.Math; 

// ...

double baseVal = Double.Parse(FirstNumber.text);
Debug.Log("First number > " + baseVal);

double exponent = Double.Parse(SecondNumber.text);
Debug.Log("Second number > " + exponent);

if (Math.Log(Double.MaxValue, baseVal) < exponent) 
{
    // a pow would overflow, so
    // do something reasonable
    return;
}

double k = Math.Pow(baseVal, exponent);
Debug.Log("Result in double > " + k);

这可能会解决一些问题。我还建议更改 if 语句。我认为统一 Mathf.Pow 是用于浮点数的,因为它有自己的浮点数数学。我不能 post 发表评论,但是,为什么要将小数的最大值添加到转换后的浮点数中?这将保证每次我想到都会溢出。就像你说的那样应该使用 checked 但是,我怀疑 Unity 会让你逃脱它吗?我不知道我是否曾经需要使用 checked 关键字。

if (!string.IsNullOrEmpty(FirstNumber.text.ToString()) & !string.IsNullOrEmpty(SecondNumber.text.ToString()))
    {
        Debug.Log("Numbers Unequal > success");
        decimal i = decimal.MaxValue;
        int j;
        float k;

        j = int.Parse(FirstNumber.text);
        Debug.Log("First number > " + j);

        //You Had First number here.
        j = int.Parse(SecondNumber.text);
        Debug.Log("Second number > " + j);

        k = Mathf.Pow(float.Parse(FirstNumber.text), float.Parse(SecondNumber.text));
        Debug.Log("Result in float > " + k);
        decimal l = Convert.ToDecimal(k);
        Debug.Log("Result in decimal > " + l);

        try
        {
            checked
            {
                l = i + l;
                Result.text = l.ToString();
            }
        }
        catch (OverflowException ex)
        {
            Debug.Log(ex);
            Result.text = l.ToString();
        }

    }
    else
    {
        Result.text = "NO NUMBERS";
    }