核心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的敏锐眼光,这似乎与版本和/或系统有关.
谢谢!
这不是一个真正的错误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)
| 归档时间: |
|
| 查看次数: |
164 次 |
| 最近记录: |