【问题标题】:Division by zero: int vs. float除以零:int vs. float
【发布时间】:2015-02-13 17:05:01
【问题描述】:

将 int 除以零会引发异常,但 float 不会 - 至少在 Java 中是这样。为什么 float 有额外的 NaN 信息,而 int 类型没有?

【问题讨论】:

  • 如果问题是关于 Java 的,为什么要标记其他语言?
  • 真正的问题在于 CPU 是如何实现的,而不是 Java 特定的。
  • 重新标记它,因为它与提到的其他语言无关。他们在不同的情况下有不同的行为。
  • @Vlad,我在发布后不久就意识到了这一点,并立即修复了它。但仍然所有这些语言都与这个特定问题无关。
  • @Sergey:你是对的,收回我的评论。

标签: c# java python vb.net math


【解决方案1】:

浮点数的表示被设计成保留一些特殊的位组合来存储special values,例如NaN、无穷大等。

int 类型没有未使用的表示形式 - 每个位模式都对应一个整数。这有很多优点:

  • 整数类型的范围尽可能大 - 不浪费位模式。
  • 整数的表示很容易理解,因为没有特殊情况。
  • 即使在非常简单的处理器上也能以极高的速度完成整数运算。

【讨论】:

  • 在实际案例中,什么时候真正需要 NaN,我不明白为什么你会想要除以零......?
【解决方案2】:

这里给出了关于浮点运算的清晰解释

http://www.artima.com/underthehood/floatingP.html

【讨论】:

    【解决方案3】:

    基本上,这纯粹是一个武断的决定。

    传统的int 尝试使用所有位来表示可能的数字,而IEEE 754 标准为NaN 保留一个特殊值。

    可以更改ints 的标准以包含特殊值,但代价是降低操作效率。开发人员通常希望int 操作非常高效,而浮点数的操作(纯粹是心理上)更允许更慢。

    【讨论】:

    • 实际上是数百万个值。 :-)
    • ~ 2^52,400 亿要挑剔。为什么需要这么多 NaN 值,我不知道。
    • 确实如此。为了清楚起见,我省略了确切的细节。
    • @Peter - 你显然不需要那么多,但它们在那里是因为 1)位模式不能(有效地)用于其他任何事情,2)将 FP 硬件限制为特定值不会'没有取得任何成就(很多),并且 3)实际上存在不同的 种类 NaN;即安静的 NaN 与发信号的 NaN。
    • @Stephen C,不知道安静与信号 NaN。我假设 Java 只支持前者。
    【解决方案4】:

    整数和浮点数在机器内部的表示方式不同。整数通常使用带符号的二进制补码表示,即(本质上)以二为底的数字。另一方面,浮点数使用更复杂的表示形式,可以容纳更大或更小的值。然而,机器为浮点数保留了几个特殊的位模式来表示数字以外的东西。例如,NaN 和正无穷或负无穷都有值。这意味着,如果您将浮点数除以零,则计算机可以使用一系列位来对您除以零的位进行编码。对于整数,所有位模式都用于对数字进行编码,因此计算机无法使用有意义的位序列来表示错误。

    不过,这不是整数的基本属性。理论上,可以通过返回一些 NaN 变体来制作一个整数表示来处理除以零。这不是在实践中所做的。

    【讨论】:

    • 嗯,至少有一些语言决定除以零给你零。
    【解决方案5】:

    Java 反映了大多数 CPU 的实现方式。整数除以零会导致 x86/x64 上的中断,而浮点除以零会导致无穷大、负无穷大或 NaN。注意:使用浮点数,您也可以除以负零。 :P

    【讨论】:

    • x86 FPU 实际上允许配置是否在除以零时引发异常,因此说浮点除以零不会导致中断有点误导——这是您的选择如果是的话。此外,浮点除以零永远不会产生 inf 或 -inf。它总是 NaN。
    • @Sven,什么? float x = 0.0f; float y = 1.0f; printf("%f\n", y / x); 为我打印“inf”。 NaN 通常是零除以零的结果。
    • @Sven,它是可配置的。 AFAIK 默认是不中断我相信的过程(或者至少这是为 C/C++ 设置的方式)并且 Java 基于 C/C++。
    【解决方案6】:

    我认为真正的原因是众所周知的事实:计算机将所有内容都存储在 0 和 1 中。

    它与整数、浮点数和零除有什么关系?这很简单。如果您只有零和一,则很容易将它们组合成整数,就像使用十进制数字一样。所以“10”变成了2,“11”变成了3,以此类推。这种整数表示是如此自然,以至于没有人会想到为整数发明任何其他东西,它只会让 CPU 更加复杂,事情更加混乱。唯一需要的“发明”是弄清楚如何存储负数,但是如果你从 x+(-x) 应该始终等于 0 的点开始,而不使用任何特殊类型的在这里补充。这就是 11111111 对于 8 位整数为 -1 的原因,因为如果将 1 加到它上面,它会变成 100000000,然后第 8 位会因溢出而被截断,而你会得到零。但是这种自然格式不能容纳无穷大和 NaN,而且没有人想为此发明一种非自然表示。好吧,如果有人真的这样做了,我不会感到惊讶,但这种格式不可能广为人知并被广泛使用。

    现在,对于浮点数,没有自然表示。即使我们将 0.5 转换为二进制,它仍然会类似于 0.1,只是现在我们有了“二进制点”而不是小数点。但是 CPU 不能自然地表示一个“点”,只有 1 和 0。所以需要某种特殊格式。根本没有别的路可走。然后有人可能会建议,“嘿,伙计们,既然我们在这里,为什么不包括无穷大和其他数字废话的特殊表示呢?”就这样完成了。

    这就是这些格式如此不同的原因。如何处理除以零,这取决于语言设计者,但对于浮点,他们可以在 inf/NaN 和异常之间进行选择,而对于整数,他们自然没有这种东西。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-04-06
      • 2014-05-25
      • 1970-01-01
      • 2021-12-03
      • 1970-01-01
      • 2020-10-22
      • 2023-01-18
      相关资源
      最近更新 更多