【问题标题】:Why does this method return double.PositiveInfinity not DivideByZeroException?为什么这个方法返回 double.PositiveInfinity 而不是 DivideByZeroException?
【发布时间】:2016-07-25 19:57:41
【问题描述】:

我在 VS2015 C# 交互中运行了以下 sn-p 并得到了一些非常奇怪的行为。

> double divide(double a, double b)
. {
.     try
.     {
.         return a / b;
.     }
.     catch (DivideByZeroException exception)
.     {
.         throw new ArgumentException("Argument b must be non zero.", exception);
.     }
. }    
> divide(3,0)
Infinity    
> 3 / 0
(1,1): error CS0020: Division by constant zero
> var b = 0;
> 3 / b
Attempted to divide by zero.
> 

为什么方法返回无穷大而 3 / 0 抛出错误而 3 / b 抛出格式化错误?我可以强制除法抛出错误而不是返回无穷大吗?

如果我将方法重新格式化为

double divide(double a, double b)
{
    if ( b == 0 )
    {
        throw new ArgumentException("Argument b must be non zero.", new DivideByZeroException());
    }
    return a / b;
}

新的 DivideByZeroException 是否包含与捕获的异常相同的所有信息和结构?

【问题讨论】:

    标签: c# exception-handling infinity dividebyzeroexception


    【解决方案1】:

    因为你使用System.Double

    MSDN 所述,DivideByZeroException 仅针对整数类型和Decimal 抛出。

    那是因为很难为 Double 值定义“所谓的”零。

    PositiveInfinity 也是由零除以正数 被除数,NegativeInfinity 由一个除以零产生 负股息。 (来源:MSDN again

    DivideByZeroException 不适用于浮点类型。注意:您可以得到NaN,但当您尝试除以零且除数为零时。

    【讨论】:

    • 但是为什么要将 PositiveInfinity、NegativeInfinity 或 NaN 用于双精度数,而不是抛出异常?这意味着代码会默默地失败,计算会继续(并且这些值会传播),结果是 a) 输出可能是垃圾,b) 用户甚至可能不知道存在问题(特别是如果代码是服务器上的后台、无人值守的进程),并且 c)如果检测到问题,则将其追溯到代码中的第一次出现将是乏味的(并且可能有很多地方可能发生)。跨度>
    • @patrickjlee 您将其标记为“失败”,但不一定如此对待。这一切都取决于任务。恕我直言,SingleDouble 在业务逻辑实现中经常被误用:如果不小心处理,这些类型的不精确会导致更大的问题。
    • @sergey-quixoticaxis-ivanov 我已经编写财务软件 30 多年了,我从未遇到过适合软件在 Infinity 之后继续运行的情况,-Infinity或 NaN 已作为计算结果生成。这种情况几乎总是由数据中的意外情况或代码中的错误导致,因此需要提醒用户有问题。因此,在我看来,当前的默认行为(在 .NET Core 3.0 及更早版本以及 .NET 4.72 及更早版本中)对此类应用程序来说是一种麻烦。
    • @patrickjlee 我非常喜欢 cmets 大约 30 年的金融软件编写经验。如果您多年来一直使用不精确的浮点类型而没有完全排序,并且从未在自己的脚下开枪,我为您感到高兴。但是我见过的所有金融软件(我应该说我只见过交易台软件)都使用精确类型(并且不是用 C# 编写的)。 C# 有一个很好的 decimal 类型,尽管它是为与金钱相关的任务量身定制的。对于与金钱无关的场景,例如科学计算和各种无穷大和 NaN 的 3D 建模非常常见。
    【解决方案2】:

    为什么方法返回无穷大而 3 / 0 抛出错误而 3 / b 抛出了一个格式化错误?

    因为在第一种情况下,0 不是整数,而是双精度数。而在第二个是一个整数。您应该在这里意识到 double 是一个浮点数。所以它没有像整数那样的精确值。另一方面,一个整数可以被计算机以 100% 的准确率表示。

    Here 你可以找到一篇关于浮点数的非常好的文章。

    【讨论】:

      【解决方案3】:

      正如其他人在上面所说,这是由于您使用 double 作为除数。您可以通过使用变量示例来证明这一点,但使用 double 而不是 var

      > double a = 3;
      > double b = 0;
      > a/b
      ∞
      

      【讨论】:

      • 感谢您指出这一点,我忘记了我使用过 var。将 0 指定为计算为无穷大的双字面值。
      【解决方案4】:

      Java 中的 Int 是 2 的补码。二进制补码整数没有任何位可用于存储 Infinity 或 NaN 等特殊值,因此由于结果无法以所需类型表示,因此必须抛出异常。浮点数没有这个问题(Infinity 有一个位模式可用),因此不需要例外。

      【讨论】:

      • 这个问题与java无关
      • 我的错!虽然它也适用于 C#。
      • @codemonger 从数学上讲 N / 0 不等于无穷大。抛出异常比返回任何值更有意义,即使考虑到浮点数支持值 +/- Infinity。 NaN 比无穷大更合适。
      • @KelsonB​​all NaN 返回 0/0。一开始就很难为浮点数定义 0。
      猜你喜欢
      • 2019-07-23
      • 2019-06-29
      • 1970-01-01
      • 2019-04-27
      • 1970-01-01
      • 1970-01-01
      • 2013-10-14
      • 2023-02-24
      • 2019-12-20
      相关资源
      最近更新 更多