为什么 Ruby 在计算 mod 时要添加 precision/digits?

Why is Ruby adding precision/digits when calculating a mod?

我需要用坐标做一些计算,遇到了 这种(至少对我而言)奇怪的行为。 有人可以解释为什么会这样吗?

$ long
=> 49.0126760222489
$ long % long.floor
=> 0.012676022248896857

我原以为最后一行的计算结果只是句点后的数字,从 long 开始,但最后一行却多了一个 6857

为什么要加数字?

信息来自哪里?

似乎与Ruby本身无关,但是:

floating point numbers that in general suffer from this type of rounding error, because they’re limited to x number of bytes, and, in general, cannot store decimal number perfectly.

Documentation

从上面的文档中,您还可以获得一些绕过本机浮动行为的选项。上面的文档可以被认为是官方文档,因为它是由 ruby-doc.org.

提供的

我想我们只是看到了 float 的错误。参见 0.0126760222489 % 1.01.0126760222489 % 1.0。你认为结果应该是相同的,但不是 - IEEE754 floats/doubles 不保证 运行 完美的结果,默认情况下这些在 Ruby 中用于存储浮点值.

甚至有点表现出来in the docs

6543.21.modulo(137)      #=> 104.21
6543.21.modulo(137.24)   #=> 92.9299999999996

可以看到第二个结果有一点误差。实际上,在 Ruby 2.3.1 我 运行 第一行得到:

pry(main)> 6543.21.modulo(137)
=> 104.21000000000004

与取模没有必然关系,也不一定可见:

[30] pry(main)> 10.0126760222489 - 0.0
=> 10.0126760222489
[31] pry(main)> 10.0126760222489 - 1.0
=> 9.0126760222489
[32] pry(main)> 10.0126760222489 - 2.0
=> 8.0126760222489
[33] pry(main)> 10.0126760222489 - 3.0
=> 7.0126760222489
[34] pry(main)> 10.0126760222489 - 4.0
=> 6.0126760222489
[35] pry(main)> 10.0126760222489 - 5.0
=> 5.0126760222489
[36] pry(main)> 10.0126760222489 - 6.0
=> 4.0126760222489
[37] pry(main)> 10.0126760222489 - 7.0
=> 3.0126760222489004

每个使用标准浮点数的软件都需要考虑这些小错误。如果由于某种原因您无法处理,那么您可以使用 bigdecimal(应该已经包含在您的 Ruby 中)、定点或一些类似的数字库

require 'bigdecimal'

BigDecimal('6543.21').modulo(137).to_s
=> "0.10421E3"

BigDecimal('6543.21').modulo(137).to_f
=> 104.21

请记住,'bigdecimal' 可能会更慢并且可能会占用更多内存。