纠正R模数误差的最佳方法是什么?

Tur*_*912 4 r modulus

核心R引擎有一个严重的缺陷,它表达了Modulus操作的输出:

ceiling((1.99 %% 1) * 100)

返回:99(正确)

ceiling((2.99 %% 1) * 100)

返回:100(不正确)

该行为将显示在任何整数值N + 2.99(例如3.99等)中.如果这与浮点表示相关联,则系统不会表达差异的完整细节.这尤其令人不安,因为:

两者(1.99 %% 1)并且(2.99 %% 1) 似乎返回0.99.

两者((1.99 %% 1) * 100)并且((2.99 %% 1) * 100) 似乎返回99.

但是,如果进行任何舍入或类似的数学运算,则2.99 的不可见残值会以意外的方式翻转.

虽然为我当前的应用程序解决这个问题是微不足道的:

floor((2.99 - floor(2.99)) * 100)

返回:99(正确)

sprintf("%.22f", floor((2.99 - floor(2.99)) * 100))

返回:99.0000000000000000000000(正确)

...我想知道有多少其他实例Modulus返回坏值而没有底层细节来显示浮点delta.有没有办法揭露模数似乎附加的基础残值?它是不可见的.

编辑:根据下面的andrew.punnett的慷慨示例,print(1.99, digits = 22)返回1.99(没有浮动扩展),而print(1.99 %% 1, digits = 22)返回0.98999999999999999.根据Aaron的敏锐眼光,这似乎与版本和/或系统有关.

谢谢!

and*_*ett 6

这不是一个真正的错误R.它实际上是浮点运算的属性.

问题出现是因为1.99或2.99都不能完全表示为浮点数.可以存储在双精度(64位)浮点数中的最接近的十进制数为2.99是2.99000000000000021316282072803(在此处尝试转换)

因此表达式评估为:

ceiling((2.99 %% 1) * 100) = ceiling(99.000000000000021316282072803)
                           = 100
Run Code Online (Sandbox Code Playgroud)

相比之下,1.99的最近表示是1.989999999999999991118215803,恰好给出了您期望的答案:

ceiling((1.99 %% 1) * 100) = ceiling(98.9999999999999991118215803)
                           = 99
Run Code Online (Sandbox Code Playgroud)

对于IEEE 754浮点运算,这两个结果都是正确的,但正如您所看到的,只有一个结果与您通过应用实数运算规则得到的结果一致.

这个问题更加复杂,因为默认行为R是截断每个浮点数print().如果要查看更多数字,则必须提供digits参数:

print(1.99, digits = 22)
Run Code Online (Sandbox Code Playgroud)

但是,即使这样也无法在所有平台上提供正确的位数,因此准确查看浮点数的更可靠方法是:

cat(sprintf("%.22f\n", 1.99))
Run Code Online (Sandbox Code Playgroud)

  • PS.很好的答案,明确但不屈尊俯就.:) 谢谢. (3认同)
  • 我认为@ andrew.punnett所说的是,R*确实*返回那个; 它只是不显示*它. (2认同)
  • 似乎还有一些特定于系统的事情正在发生; 对于`print(1.99,digits = 22)`我得到`1.989999999999999991118`. (2认同)