添加两个 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
运算符;与强制浮点除法的方式相同。
您可以有 两个 种可能的溢出情况:
- 两大阳性
value
和adder
return非阳性结果
- 两大负
value
和adder
return非负结果
因此您必须检查 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)
这里,value
和adder
都是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;
}
}
我试图在两种情况下防止溢出,一种是将 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
运算符;与强制浮点除法的方式相同。
您可以有 两个 种可能的溢出情况:
- 两大阳性
value
和adder
return非阳性结果 - 两大负
value
和adder
return非负结果
因此您必须检查 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)
这里,value
和adder
都是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;
}
}