为什么从numpy到OS会有不同的asinh输出?

时间:2018-10-31 16:39:54

标签: python numpy floating-point operating-system

我正在尝试在整个操作系统上保持一致的浮点计算结果,并且在较新的系统上进行测试时遇到了关于numpy和arcsinh的奇怪回归。这是一个最小的工作示例,在整个系统中的行为各不相同。

#!/usr/bin/env python
import struct

from numpy import (array, arcsinh, float32)


def float_to_hex(f):
    return hex(struct.unpack('<I', struct.pack('<f', f))[0])


numpy_result = arcsinh(array([3.0], dtype=float32))[0]
print("asinh(3.0):", numpy_result, float_to_hex(numpy_result))

在Centos 7和Ubuntu 16.04上,我得到以下结果: asinh(3.0): 1.8184464 0x3fe8c2da

在Ubuntu 18.04(和Windows,根据一位同事)上,我得到以下结果: asinh(3.0): 1.8184465 0x3fe8c2db

很高兴了解为什么会这样,以及如何在系统之间获得一致的结果。理想情况下,坚持使用32位浮点解决方案。我有一些忽略整个操作系统的更改的numpy选项吗?

值得注意的是,我无法使用C程序重现此内容。使用GLIBC的asinh(具有32位浮点数3.0),我始终总是得到新的结果1.8184465,无论使用什么系统,它都是0x3fe8c2db十六进制表示。这似乎是具体的。

我的工作C示例:

#include <stdio.h>
#include <math.h>

int main() {
    float value = asinhf(3.0f);
    unsigned int hexValue = *(unsigned int *)&value;
    printf("Plain value: %.7f\n", value);
    printf("Hex value: 0x%8x\n", hexValue);
    return 0;
}

我还可以验证整个系统是否使用了完全相同的numpy版本。在这种情况下,它是1.15.3。 numpy软件包从各处安装,因此安装了相同的共享库。出于我的理智,我通过在所有系统中对所有库运行file操作来仔细检查了库。

我认为,根据IEEE 754,最后一个有效数字5(对于arcsinh为3.0)是正确的,因为它应从零舍入。但是,结果一致的解决方案对我来说更重要。

谢谢您的时间。

1 个答案:

答案 0 :(得分:2)

所以我发现了为什么答案在系统之间是不同的,而且我以前没有看到过。但是,我仍然不确定如何获得一致的结果。

正如Mark Dickinson在评论中指出的那样,我忽略了gcc正在使用MPFR(具有正确舍入的多精度浮点)执行编译时优化。在生成的二进制文件上运行ldd表示libm根本没有动态加载。我用clang重新编译了我的C示例,并在libm中动态链接,瞧瞧,我得到的结果与在整个系统中通过python / numpy取得的结果完全相同。结果是asinhf(3.0f);在旧系统上四舍五入,在新系统上四舍五入。

因此,在某种程度上,这看起来像是libm库的更新。

具体来说,GLIBC的变化至少发生在2.23和2.27之间。

如果有人对在系统之间进行一致的取整有任何建议,我将不胜感激。我怀疑不管旧系统的精度如何,舍入都可能不正确。

谢谢您的时间。