(C#) 我应该在计算中防范 Infinity/-Infinity 吗? IE。抛出溢出异常?

(C#) Should I Guard Against Infinity/-Infinity in my calculations? I.e. Throw an Overflow Exception?

C#.

中寻找关于 Infinity/-Infinity 的一些建议

我目前正在为 Rectangle/Circle 等形状构建几何体 类。 用户将分别为 Width/Depth 和直径提供输入

这些属性将是 double,我知道如果你将 double.MaxValue 乘以 2,而不是明确地 溢出 ,那么你会得到+无限等

每个形状 类 都将具有其他属性,例如面积、周长等。 因此,即使提供的维度小于 MaxValue,如果用户愿意,计算值也有可能是一个巨大的数字:

例如Math.PI x Math.Pow(diameter, 2) / 4 => Math.PI x Math.Pow(double.MaxValue, 2) / 4

(即,即使用户提供了 MaxValue 作为输入,此方法也会导致 +infinity。)

我的问题是我是否应该一直提防无穷大? 如果用户值或计算值进入无穷大,我是否应该抛出异常(OverflowException)?

看起来它可能是 code smell 检查这些几何 [=] 中的 every property/method 的无穷大50=]... 有没有更好的方法?

public double Area
{
    get
    {
        double value = Math.PI * Math.Pow(this.diameter, 2) / 4;
        if (double.IsInfinity(value)
        {
            throw new OverflowException("Area has overflowed.");
        }
    }
}

public double Perimeter
{
    get
    {
        double value = Math.PI * this.diameter;
        if (double.IsInfinity(value)
        {
            throw new OverflowException("Perimeter has overflowed.");
        }
    }
}

感谢您的时间和想法! 干杯。

Each of the shape classes will have additional properties such as Area, Perimeter etc. Therefore, even if the provided dimensions are less than MaxValue, there is a chance that computed values could be a huge number if the user was so inclined

double max 是 1.7976931348623157E+308,担心用户输入的几何数据会达到该限制是没有意义的。简单地归还无穷大,它可能永远不会发生。换句话说,以微米为单位,到比邻星的距离约为 4,014 × 10^22,因此您会发现担心这个是多么浪费时间。

为了至少给用户一个合理的选择,你可以让他定义你的几何环境中的一个单位代表什么;一微米、毫米、米、公里、光年、秒差距等等,所以他总是保持合理的比例。

从概念上讲,您遇到了设计问题。导致无限区域的值会导致您的形状处于无效状态。

例如,假设所讨论的形状是圆形。任何传递的导致 Area > double.MaxValue 的值都是无效状态。换句话说,任何值 diameter 其中 Math.PI * Math.Pow(diamater, 2) > double.MaxValue 无效。

diameter 求解 double.MaxValue = Math.PI * Math.Pow(diamater, 2)(它是 1.5129091144565236E+154,欢迎您验证我的数学),并在构造函数中检查

private const double MaxDiameter = 1.5129091144565236E+154;
Circle(double diameter) 
{
    if (diameter > MaxDiameter) 
    {
        throw ArgumentOutOfRangeException(); 
    }
}

--

None 以上可能很重要

在实践中,请考虑以下内容。已知宇宙的直径大约是30千兆秒差距,换算成普朗克长度(我能想到的最小距离单位)大约是5.7e61,也就是远,far低于double.MaxValue.

我不担心您的属性会出现双重溢出。设计你的形状是明智的,这样你就可以使用你定义的单位类型,所以你总是知道你正在使用什么单位。

public Circle(Meters diamater)
public Rectangle(Meters width, Meters height)

对无限值抛出异常是一种设计选择

IMO,没有 "good answer" 这个,这取决于你想如何使用你的 classes。例如,如果目标是绘图,则防止出现巨大值可能是有意义的。

对于计算和比较,我不会是确定的。为 IEEE 标准浮点值定义的 Inf-Inf(以及 NaN)值是一致的。 class 的用户知道您正在使用 double,因此,期待他们的所有功能是合理的。

哪个形状的面积最大,是边长为 10 个单位的正方形还是大到您认为无限大的圆?答案是一致的,因为 Inf > 100true.

如果你打算失败,早点失败

如果您决定继续(合理的)异常路径,我建议您尽早失败。

这意味着,不要在 getter 中计算面积/周长,而是尽快计算面积和周长(如果您的 class 是不可变的,则在构造函数中,或者在相关其他属性的设置器中,例如直径/长度等)并检查当时是否有无穷大的值。

此外,还要检查 NaNs 值。

class Circle
{
    public Circle(double diameter) 
    {
        if (double.IsInfinity(diameter) || double.IsNaN(diameter))
        {
            throw new ArgumentOutOfRangeException(nameof(diameter));
        }
        Diameter = diameter;

        Perimeter = Math.PI * diameter;
        if (double.IsInfinity(Perimeter))
        {
            throw new OverflowException("Perimeter has overflowed.");
        }
    }

    double Diameter { get; }
    double Perimeter { get; }
}