【问题标题】:How to detect a potential overflow如何检测潜在的溢出
【发布时间】:2014-09-01 11:20:39
【问题描述】:

好的,考虑以下场景:

 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 有符号整数来表示分子和分母。如果尝试逼近的数字大于或小于RationalNumber 可以表示的最大或最小数字,即long.MaxValuelong.MinValue,我希望我的方法抛出System.OverflowException

我的第一次尝试非常简单和天真:

 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

我的第二次尝试更像是一种 hack(我觉得它有点丑),但考虑到算法需要做什么,如果 integerParttarget 没有相同的符号,我可以检测到溢出;这必然意味着发生了溢出。所以我的第二次尝试看起来像这样:

 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 足够大,则可能会发生溢出而无需更改符号。

我确信必须有一种完全明显和愚蠢的方式来做到这一点,而我完全错过了它。有人可以告诉我方法并结束我在这个特定问题上的痛苦吗?

【问题讨论】:

    标签: c#


    【解决方案1】:

    ckecked 关键字通过抛出 OverflowException 来帮助您的代码捕获运行时发生溢出的情况。

    // Checked block. 
    checked
    {
        int i3 = 2147483647 + 10; // throws
        Console.WriteLine(i3);
    }
    

    根据您在另一个线程上与 usr 的讨论,我们可以推断,为了在 double 中捕获您的 long 值下限的溢出,您必须转到 1025d - long.MinValue。因此,看起来您的下限必须考虑到您的小数类型的尾数大小,以便正确处理转换回long

    这是一种非常讨厌的解决方法,并且不会产生非常可读的代码......

    【讨论】:

    • 考虑我的场景:我有一个double 类型的参数,我必须弄清楚它是否会作为long 溢出。如果我传递给方法-1d + long.MinValue,即使在checked 上下文中,当我将它转换为长(long)(-1d + long.MinValue) 时,我仍然不会得到OverFlowException。不过,它确实会抛出 1d + long.MaxValue
    • 这真的很奇怪:我现在正在调查它,因为我认为精度损失来自您将-1d + long.MinValue 保持为双格式,但精度损失没有被捕获选中的关键字。
    • 如果你写var x = ((long)-1d + long.MinValue);,代码就可以工作,太糟糕了。
    • 是的,那是因为你为计算的所有成员都在 long 中工作,但是 var x = (long)(-1d + long.MinValue); 不会抛出,因为 double 到 long 的转换没有考虑数据丢失。跨度>
    • FrancescoDiLisi:是的,但这对我没有帮助。我需要知道 double 参数是否溢出。您的代码直接传入long
    猜你喜欢
    • 1970-01-01
    • 2010-09-17
    • 2016-05-22
    • 2014-07-20
    • 2016-10-02
    • 2023-03-22
    • 2015-08-28
    • 2010-10-19
    • 1970-01-01
    相关资源
    最近更新 更多