11

我试图找出红宝石如何处理零除法。Ruby 根据类返回不同的结果。这是我尝试过的

0/0     # => ZeroDivisionError: divided by 0    
1/0     # => ZeroDivisionError: divided by 0
1.0/0   # => Infinity
0.0/0.0 # => NaN

这里发生了什么?我不应该ZeroDivisionError为上述所有情况得到一个吗?

更新“Infinity”是标准数据类型吗?

(1.0/0).class  # => Float
4

3 回答 3

11

Ruby 只跟踪IEEE 754 浮点标准。该维基百科页面在解释您所看到的内容方面并不差。许多现代语言采用相同的方法。

直觉上,你看到的行为是完全合理的。一般来说,

1/<small number> = <big number>

因此在极限内,

1/0 -> Infinity    and similarly    -1/0 -> -Infinity

Infinity是浮点子系统可以理解的常数。另一方面

0 / <any non-zero> = 0

所以我们在 0/0 上发生了冲突。它应该是零还是无穷大?IEEE 标准答案是“不是数字”,NaN您看到的是另一个浮点常数。

常量NaN和正负Infinity以一种有意义的方式通过表达式传播。例如:

Infinity + <any (necessarly finite) number> = Infinity

<any number> + NaN = NaN

更有趣的是:

1 / Infinity = 0

您可以自己尝试:

irb(main):005:0> 1.0 / (1.0 / 0.0)
=> 0.0

以这种方式,浮点计算可以继续,即使它已经溢出或被零除,并且仍然会产生一个合理的信息答案(尽管在你很好地了解标准之后,你会发现依赖答案通常是一个坏主意)。

这远非标准提供的唯一行为。可以选择其他的。但是 Ruby 会为您做到这一点。源文件numeric.c, functionInit_Numeric设置主机处理器,以便除以零传播无穷大。其他语言可能会做出其他选择,例如生成异常。

于 2013-08-08T12:07:07.607 回答
7

浮点的行为反映了IEEE 754中的标准:

  • 无效操作(例如,负数的平方根)(默认返回qNaN)。
  • 除以零(对有限操作数的运算给出精确的无限结果,例如 1/0 或 log(0))(默认返回±infinity)。

为整数除以零实现运行时错误的决定在许多其他语言以及 Java、C++、Python 中很常见。Python 实际上也调用了错误ZeroDivisionError

有关这些分类和行为的原因,请参阅sawa 的回答。

于 2013-08-08T12:16:01.217 回答
5

关键是浮点数有舍入误差。浮点数0.0不一定表示精确的零或数学意义上的 0.0,而是代表将四舍五入到0.0给定精度的所有数字。0.0除以精确 0 没有数学定义,但如果除数碰巧有一个非零绝对值小到可以四舍五入到,则禁止除以将有返回错误的危险0.0。您不希望程序在除数的绝对值不为零时突然返回错误。在浮点数的情况下,让系统分配一个特定的数字来除以更安全0.0而不是禁止它。但是这个数字不能用正常的方式表示,所以它被分配为 NaN 或 Infinity。令人误解的是,无穷大不是数学意义上的无穷大。它只是意味着“一个比这个系统中可以表达的任何其他数字都大的数字”。这解释了以下情况:

1.0/0.0 # => Infinity
0.0/0.0 # => NaN

当一个参数/是浮点数时,Ruby 将另一个参数强制转换为浮点数,所以

1/0.0
1.0/0

将与 相同1.0/0.0

另一方面,整数0不包含错误,并且精确为零,因此不存在这种危险。提出零除法错误更有意义。这解释了

1/0 # => Error
0/0 # => Error
于 2013-08-08T12:28:59.180 回答