如何检测潜在的溢出
本文关键字:溢出 检测 何检测 | 更新日期: 2023-09-27 18:20:23
好的,请考虑以下场景:
public static bool TryGetNearestRationalNumber(double target, double precision, out RationalNumber nearest)
{
//implements continued fractions to solve the problem. Only relevant code is shown.
var integerPart = (long)target; //necessary for algorithm
var fractionalPart = target - integerPart; //necessary for algorithm,
....
}
RationaNumber
内部使用两个Int64
有符号整数来表示分子和分母。我希望我的方法抛出一个System.OverflowException
,如果尝试近似的数字大于或小于可以用 RationalNumber
表示的最大或最小数字,它们是long.MaxValue
和long.MinValue
。
我的第一次尝试非常简单和天真:
public bool TryGetNearestRationalNumber(double target, double precision, out Foo foo)
{
//check overflow here
if (target > long.MaxValue || target < long.MinValue)
throw new OverFlowExcetpion();
//implements continued fractions to solve the problem. Only relevant code is shown.
var integerPart = (long)target; //necessary for algorithm
var fractionalPart = target - integerPart; //necesarry for algorithm,
...
}
当我打电话给TryGetNearestRationalNumber(1f + long.MaxValue, precision, nearest)
或TryGetNearestRationalNumber(-1f + long.MinValue, precision, nearest)
时,这失败得很惨。显然,这是因为对于如此大或小的数字,double
没有足够的分辨率来检测潜在的溢出,并且if
条件都不会解析为true
。
我的第二次尝试更像是一个黑客(我觉得它有点丑陋(,但考虑到算法需要做什么,如果integerPart
和target
没有相同的标志,我可以检测到溢出;这必然意味着溢出发生了。所以我的第二次尝试看起来像这样:
public bool TryGetNearestRationalNumber(double target, double precision, out Foo foo)
{
//implements continued fractions to solve the problem. Only relevant code is shown.
var integerPart = (long)target; //necessary for algorithm
if ((integerPart < 0 && target > 0) || (integerPart > 0 && target < 0)) //yuck!
throw new OverFlowException();
var fractionalPart = target - integerPart; //necesarry for algorithm,
}
问题是这也行不通。它确实适用于最大值溢出TryGetNearestRationalNumber(1f + long.MaxValue, precision, nearest)
但再次惨遭失败,最小值溢出TryGetNearestRationalNumber(-1f + long.MinValue, precision, nearest)
。最重要的是,这个解决方案远非完美,因为给定足够大的target
,溢出可以在不改变符号的情况下发生。
敢肯定,必须有一种完全明显和愚蠢的方式来做到这一点,我完全错过了它。有人可以给我指路并结束我在这个特定问题上的痛苦吗?
ckecked 关键字通过抛出OverflowException
来帮助您的代码捕获运行时是否发生溢出。
// Checked block.
checked
{
int i3 = 2147483647 + 10; // throws
Console.WriteLine(i3);
}
在您的另一个线程上与 usr 讨论之后,我们可以推断出,为了捕获双精度值中多头值下限的溢出,您必须下降到 1025d - long.MinValue
。因此,看起来您的下限必须考虑十进制类型的尾数大小,以便正确处理回long
。
作为一种解决方法,它非常令人讨厌,并且不能使代码非常易读......