算术运算如何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";
}
我刚开始接触 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";
}