R 浮点运算与再现性

R 浮点运算与再现性,r,floating-point,ieee-754,R,Floating Point,Ieee 754,IEEE-754算法是否可在不同平台上复制 我在测试一些用R编写的代码,它使用随机数。我认为在所有测试平台上设置随机数生成器的种子将使测试具有可重复性,但对于生成指数分布随机数的rexp(),情况似乎并非如此 这是我在32位Linux上得到的: options(digits=22) ; set.seed(9) ; rexp(1, 5) # [1] 0.2806184054728815824298 sessionInfo() # R version 3.0.2 (2013-09-25) # Pla

IEEE-754算法是否可在不同平台上复制

我在测试一些用R编写的代码,它使用随机数。我认为在所有测试平台上设置随机数生成器的种子将使测试具有可重复性,但对于生成指数分布随机数的
rexp()
,情况似乎并非如此

这是我在32位Linux上得到的:

options(digits=22) ; set.seed(9) ; rexp(1, 5)
# [1] 0.2806184054728815824298
sessionInfo()
# R version 3.0.2 (2013-09-25)
# Platform: i686-pc-linux-gnu (32-bit)
这就是我在64位OSX 10.9上得到的结果:

options(digits=22) ; set.seed(9) ; rexp(1, 5)
# [1] 0.2806184054728815269186
sessionInfo()
# R version 3.0.2 (2013-09-25)
# Platform: x86_64-apple-darwin10.8.0 (64-bit)
64位Linux提供了与64位OSX相同的结果,因此这似乎是一个32位vs 64位的问题

让我们假设两个R版本都使用相同的GCC版本进行编译,并且使用相同的(默认R)编译标志使编译器使用IEEE-754算法

我的问题是,这能被认为是R中的一个bug吗?或者这仅仅是使用近似、有限精度浮点运算的“正常”结果

我向R-devel邮件列表发送了相同的问题,但列表上没有答案,只有一个私下的答案,试图说服我这不是一个bug,我应该接受它

这是IEEE-754关于再现性的说法(来自维基百科):

IEEE 754-1985允许在实现中有许多变化(例如 某些值的编码和某些异常的检测)。 IEEE 754-2008已经收紧了其中的许多,但也有一些变化 仍然保留(特别是对于二进制格式)。再现性 该条款建议语言标准应提供一种 编写可复制的程序(即产生相同结果的程序 生成一种语言的所有实现),并描述需要什么 为获得可重复的结果而进行的操作

这是在“建议”之下


我(主观)的意见是,这是一个缺陷,因为IEEE-754标准的整个要点是具有可复制的、独立于平台的浮点算法

即使是高级语言中的基本浮点操作,其再现性也存在问题,但它们通常可以通过各种平台特定的操作来控制,例如设置编译器开关、使用自定义代码设置浮点控件和模式,或者在必要时在汇编中编写基本操作。正如注释中所述,您遇到的具体问题可能是不同的C实现使用不同的精度来计算中间浮点表达式。通常,这可以通过编译器开关或在表达式中包含强制转换和赋值来控制,以要求舍入到标称类型(从而丢弃多余的精度)

然而,更复杂的功能,如
exp
cos
,在不同的平台上通常不可重复。尽管2008年IEEE-754标准建议使用正确的舍入实现这些函数,但对于运行时已知有界的任何数学库,此任务尚未完成世界上没有人做过这样的数学运算。

已经实现了一些具有已知运行时界限的函数,但工作不完整。(根据Pascal Cuoq的评论,当CRlibm没有经过验证的正确舍入的运行时界限时,由于计算精度非常高,它会返回到一个很可能被正确舍入的结果。)弄清楚如何在限定的时间内提供正确舍入的结果,并证明这对于许多函数来说是困难的。(考虑如何证明
cos(x)的值不存在)
,其中
x
是任何
double
值,距离两个可表示值之间的中点
e
较近。中点很重要,因为它是四舍五入必须从一个结果返回到另一个结果的地方,并且
e
告诉您必须精确地返回一个结果计算近似值以提供正确的舍入。)

目前的情况是,数学库中的许多函数都是近似的,一些精度比正确的舍入要低,并且不同的供应商使用不同的近似实现。我假设
R
在其
rexp
实现中使用了其中一些函数,并且它使用了其目标平台的本机库,因此在不同的平台上会得到不同的结果


为了解决这个问题,你可以考虑在你的目标平台上使用一个通用的数学库(可能是CRILBM)。谢谢你的解释,我当然不认为这很简单,但是我希望它是为一组基本的操作而完成的,休息来自于这些。我仍然认为在这种特殊情况下,它是一个可以修复的bug(我总有一天会尝试),因为这就是

rexp
所做的一切:
unif_rand()
似乎可以跨平台复制。@GaborCsardi:假设
unif_rand
也不包含任何非基本函数,我怀疑区别在于,32位Linux的GCC编译在其算术中使用了额外的精度(
longdouble
),即使标称类型是
double
)。可能会有一个开关来控制这一点。从技术上讲,CRlibm提供了已知运行时边界的有界执行时间:对于最坏情况未知的函数的非精确情况,它只会将计算精度提高到512位。这意味着对于某些函数,它不是正确的四舍五入,而是“以天文数字的置信度正确地四舍五入”。在前面评论的“512位”部分的第1.3.5节中讨论了这些备选方案,我无法再次找到其来源。无论如何,有些“天文数字”的东西。@PascalCuoq:谢谢,我在答案中加入了一条关于这一点的注释。
digits=22
超出了您的机器限制;请参见
.Machin