【问题标题】:Why do int and decimal throw DivideByZeroException but floating point doesn't?为什么 int 和 decimal 会抛出 DivideByZeroException 而浮点却不会?
【发布时间】:2013-09-15 04:59:44
【问题描述】:

根据http://msdn.microsoft.com/en-us/library/system.dividebyzeroexception.aspx 只有 Int 和 Decimal 会在将它们除以 0 时抛出 DivideByZeroException,但是当将浮点数除以 0 时,结果是无穷大、负无穷大或 NaN。为什么是这样?有哪些结果是 +ve infinity、-ve infinity 或 NaN 的示例?

【问题讨论】:

标签: c# dividebyzeroexception


【解决方案1】:

IEEE 标准委员会felt that exception handling was more trouble than it was worth,关于可能遇到此类浮点数学问题的代码范围:

陷阱可用于停止程序,但不可恢复的情况极为罕见。
[...]
标志提供可预测的控制流和速度。它们的使用要求程序员了解异常情况,但标记粘性允许程序员延迟处理异常情况,直到必要时。

对于习惯于使用异常处理功能深入人心的语言(如 C#)的开发人员来说,这可能看起来很奇怪。 IEEE 754 标准的开发人员正在考虑更广泛的实现(例如嵌入式系统),而这些设施不可用或不可取。

【讨论】:

    【解决方案2】:

    迈克尔的回答当然是正确的。这是另一种看待它的方式。

    整数是精确的。当您将 7 除以 3 整数时,您实际上是在问一个问题:“在我必须进入负数之前,我可以从 7 中减去多少次?”。除以零是未定义的,因为没有次数可以从七中减去零得到负数。

    浮点数本质上是不精确的。它们具有一定的精度,您最好假设“真实”数量介于给定浮点数和附近的浮点数之间。此外,浮点数通常表示物理量,其测量误差远大于表示误差。我认为浮点数是围绕一个点的模糊涂抹区域。

    因此,当您在浮点数中将七除以零时,可以将其视为将某个合理接近 7 的数字除以某个合理接近零的数字。显然,一个合理地接近零的数字可以使商任意大!因此,这是通过给出无限作为答案向你发出的信号;这意味着答案可以任意大,具体取决于真实值的实际位置。

    【讨论】:

    • 因此,没有真正的“零”浮点数,你不能真正除以 0f。
    【解决方案3】:

    处理器内置的浮点引擎非常有能力生成浮点除以零的异常。 Windows 有一个专门的异常代码,STATUS_FLOAT_DIVIDE_BY_ZERO,异常代码 0xC000008E,“浮点除以零”。以及 FPU 可以报告的其他事故,例如上溢、下溢和不精确的结果(也称为非规范化)。

    是否这样做是由控制寄存器决定的,程序可以使用像_controlfp()这样的辅助函数来改变这个寄存器。例如,使用 Borland 工具创建的库通常会这样做,以消除这些异常。

    委婉地说,这并没有奏效。这是你能想象到的最糟糕的全局变量。将此类库与期望除以零以生成无穷大而不是异常的其他库混合是行不通的,而且几乎不可能处理。

    因此,现在语言运行时屏蔽所有浮点异常已成为常态。 CLR 也坚持这一点。

    处理一个揭露异常的库很棘手,但有一个愚蠢的解决方法。您可以抛出异常并再次捕获它。 CLR 中的异常处理代码会重置控制寄存器。 this answer 中显示了这方面的一个示例。

    【讨论】:

      猜你喜欢
      • 2013-02-18
      • 1970-01-01
      • 2014-06-22
      • 2023-02-04
      • 1970-01-01
      • 1970-01-01
      • 2010-12-14
      相关资源
      最近更新 更多