为什么 Ruby 中有 0.0 和 -0.0?

Why do we have 0.0 and -0.0 in Ruby?

在 ruby 中,为什么我可以为 0.0 浮点数指定一个负号,这个功能有什么用吗?有人可以给我解释一下吗?

-0.0
#=> -0.0

-0.0 * -1
#=> 0.0

这不是Ruby的特性,而是浮点数规范的一部分。参见 this answer。负零等于正零:

-0.0 == 0.0
# => true

您可以在 Ruby 中为 0.0 浮点数分配一个负号,因为所有 IEEE 754 浮点数都有一个 符号位 来指示数字是否是正还是负。

这里是2.5-2.5的二进制表示:

[2.5].pack('f').unpack1('b*')
#=> "00000000000000000000010000000010"

[-2.5].pack('f').unpack1('b*')
#=> "00000000000000000000010000000011"

最后一位是符号位。请注意,所有其他位都是相同的。

另一方面,符号位为0的零:

['00000000000000000000000000000000'].pack('b*').unpack1('f')
#=> 0.0

和符号位为 1 的零:

['00000000000000000000000000000001'].pack('b*').unpack1('f')
#=> -0.0

虽然0.0-0.0在数值上是相等的,但在对象层面上它们并不相同:

(0.0).eql?(-0.0)   #=> true
(0.0).equal?(-0.0) #=> false

负零有一些special properties。 例如:

1 / 0.0    #=> Infinity
1 / -0.0   #=> -Infinity

显式分配 - 并不是获得 -0.0 的唯一方法。作为基本算术运算的结果,您还可能得到 -0.0

-1.0 * 0 #=> -0.0

数学运算有实数结果,但我们将这些实数结果映射到最近的浮点数,称为"rounding"。对于每个浮点数,都有一个 范围 的实数将四舍五入到该浮点数,有时将浮点数视为用该实数范围标识是有用的。

由于浮点数的供应有限,因此必须有一个最小的正浮点数,及其相反的最小(量级)负浮点数。但是,对于比 那些 更小的实数结果会发生什么?好吧,他们必须 "round to zero"。但是 "a really small number greater than zero" 和 "a really small number less than zero" 是完全不同的东西,具有完全不同的数学 行为 ,所以我们为什么要失去它们之间的区别,仅仅因为我们四舍五入?我们不必。

因此,浮点数 0 不仅包括实数 0,还包括太小而无法表示的 正数 数量。浮点数 -0 包含太小而无法表示的 negative 数量。当您在算术中使用它们时,它们遵循 "negative times positive equals negative; negative times negative equals positive" 等规则。尽管我们在四舍五入过程中几乎忘记了这些数字的所有内容,但我们仍然没有忘记它们的符号。

您可能需要 -0.0 的一个示例是在处理函数(例如切线、正割或余割)时,其垂直极点需要朝正确的方向移动。您最终可能会除以得到负无穷大,并且您不想将其绘制为垂直线上升到正无穷大。或者你可能需要一个函数的正确符号从下面渐进地接近 0,就像你有一个负数的指数衰减并检查它是否保持负数。