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位与64位问题。
让我们假设两个R版本都使用相同的GCC版本编译,并使用相同的(默认R)编译标志,使编译器使用IEEE-754算法。
我的问题是,这可以被视为R中的错误吗?或者它只是使用近似有限精度浮点运算的“正常”结果?
我向R-devel邮件列表发送了同样的问题,但是没有在列表中得到答案,只有一个答案是私下的,试图说服我这不是一个错误,我应该忍受它。
这是IEEE-754关于再现性的说法(来自维基百科):
IEEE 754-1985允许实现中的许多变化(例如 某些值的编码和某些异常的检测)。 IEEE 754-2008已经收紧了许多这些,但有一些变化 仍然存在(特别是对于二进制格式)。再现性 条款建议语言标准应提供一种方法 写出可重现的程序(即产生相同程序的程序) 导致语言的所有实现),并描述需要什么 要做到可以获得可重复的结果。
这是在“建议”下。
我的(主观)观点认为这是一个错误,因为IEEE-754标准的重点是具有可重现的,与平台无关的浮点运算。
答案 0 :(得分:19)
在高级语言中甚至可以重现基本浮点运算的问题,但它们通常可以通过各种特定于平台的操作来控制,例如设置编译器开关,使用自定义代码设置浮点控制和模式,或者,如有必要,在装配中编写基本操作。正如在注释中开发的那样,您遇到的具体问题可能是不同的C实现使用不同的精度来评估中间浮点表达式。通常这可以通过编译器开关控制,或者通过在表达式中包含强制转换和赋值来要求舍入到标称类型(从而丢弃过多的精度)。
但是,更复杂的功能(例如exp
和cos
)在不同平台上不能常规重现。尽管2008 IEEE-754标准建议使用正确的舍入来实现这些功能,但是对于任何已知有限运行时间的数学库,此任务尚未完成。 世界上没有人做过数学来实现这一目标。
CRlibm project已经实现了一些具有已知运行时限制的函数,但工作不完整。 (Per Pascal Cuoq的评论,当CRlibm没有经过验证的正确舍入运行时限时,由于计算精度非常高,它很可能会被正确舍入的结果。)找出如何正确传递接地导致有限的时间并且证明它对于许多功能来说是困难的。 (请考虑如何证明cos(x)
x
的任何double
值都不比两个可表示值之间的中点距离e
更近。中点很重要,因为在返回一个结果到返回另一个结果时舍入必须改变,e
告诉您为了提供正确的舍入,您必须准确和精确地计算近似值。)
当前的事态是数学库中的许多函数是近似的,一些准确性比正确的舍入更加松散,并且不同的供应商使用具有不同近似的不同实现。我假设R
在其rexp
实现中使用了其中一些函数,并且它使用了其目标平台的本机库,因此它在不同平台上获得了不同的结果。
要解决此问题,您可以考虑在目标平台上使用通用数学库(可能是CRlibm)。