简体   繁体   English

与Mac和Linux上的exp函数略有不同的结果

[英]Slightly different result from exp function on Mac and Linux

The following C program produces different results on my Mac and on Linux. 以下C程序在Mac和Linux上产生不同的结果。 I'm suprised because I assumed that the implementation of libm is somehow standardized 我很惊讶,因为我认为libm的实现是某种标准化的

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

int main()
{
  double x18=-6.899495205106946e+01;
  double x19 = exp(-x18);
  printf("x19     = %.15e\n", x19);
  printf("x19 hex = %llx\n", *((unsigned long long *)(&x19)));
}

The output on Mac is 在Mac上的输出是

x19     = 9.207186811339878e+29
x19 hex = 46273e0149095886

and on Linux 在Linux上

x19     = 9.207186811339876e+29
x19 hex = 46273e0149095885

Both were compiled without any optimization flags as follows: 两者都编译时没有任何优化标志,如下所示:

gcc -lm ....

I know that I never should compare floats to be excatly the same. 我知道我绝不应该将浮点数完全相同。

This issue came up during debugging, regrettably the algorithm using this calculation proofs to be numerically unstable and this slight difference leads to significant deviations in the final result. 这个问题是在调试过程中出现的,令人遗憾的是,使用该计算证明的算法在数值上是不稳定的,并且这种微小的差异导致最终结果出现明显的偏差。 But this is a different problem. 但这是一个不同的问题。

I'm just surprised that such basic operations as exp are not standardized as I can expect for the basic algebraic operations specified by IEEE 754. 令我惊讶的是, exp等基本操作未标准化,正如我对IEEE 754指定的基本代数操作所期望的那样。

Are there any assumptions about precision I can rely on for different implementations of libm for different machines or for different versions ? 对于不同机器或不同版本的libm不同实现,是否可以依靠精度进行任何假设?


Because of the discussion below I used mpmath to compute the value with higher than machine precision and I get with two more figures the result 9.2071868113398768244 , so for both of my results the last figure is already wrong. 由于下面的讨论,我使用了mpmath来计算比机器精度更高的值,并且再得到两个数字,结果为9.2071868113398768244 ,所以对于我的两个结果,最后一个数字已经是错误的了。 The result on linux can be explained by down rounding this value, the Mac result is also off if the computer uses up rounding. linux上的结果可以通过对该值进行四舍五入来解释;如果计算机使用四舍五入,Mac结果也将关闭。

The C99 Specification states (other version should be similar): C99规范指出(其他版本应该相似):

J.3 Implementation-defined behavior J.3实现定义的行为

1 A conforming implementation is required to document its choice of behavior in each of the areas listed in this subclause. 1需要一个一致的实现来记录其在本子节中列出的每个区域中的行为选择。 The following are implementation-defined: 以下是实现定义的内容:

... ...

J.3.6 Floating point J.3.6浮点数

— The accuracy of the floating-point operations and of the library functions in <math.h> and <complex.h> that return floating-point results (5.2.4.2.2). —浮点运算和<math.h><complex.h>中返回浮点结果的库函数的准确性(5.2.4.2.2)。

Meaning GNU libm and BSD libm are free to have different levels of accuracy. 意味着GNU libm和BSD libm可以自由地具有不同级别的准确性。 Likely what is happening, is that the BSD implemention on OSX rounds to the nearest (unit in the last place) ULP, and the GNU implementation truncates down to the next ULP. 可能发生的情况是,OSX上的BSD实现四舍五入到最近的ULP(最后一个单元),而GNU实现截短到下一个ULP。

IEEE-754 behavior is specified at the binary level. IEEE-754行为是在二进制级别上指定的。 Using a Linux, I get identical values for Python's native math library, mpmath , and MPFR (via gmpy2 ). 使用Linux,我获得了Python的本地mathmpmath和MPFR相同的值(通过gmpy2 )。 However, conversion to decimal varies between the three methods. 但是,在三种方法之间,转换为十进制会有所不同。

>>> import mpmath, gmpy2
>>> import mpmath, gmpy2, math
>>> x18=68.99495205106946
>>> x19=math.exp(x18)
>>> mp18=mpmath.mpf("68.99495205106946")
>>> mp19=mpmath.exp(mp18)
>>> gp18=gmpy2.mpfr("68.99495205106946")
>>> gp19=gmpy2.exp(gp18)
>>> x18 == mp18
True
>>> x18 == gp18
True
>>> x19 == mp19
True
>>> x19 == gp19
True
>>> print(x18, mp18, gp18)
68.99495205106946 68.9949520510695 68.994952051069461
>>> print(x19, mp19, gp19)
9.207186811339876e+29 9.20718681133988e+29 9.2071868113398761e+29

After conversion to Python's arbitrary precision integer form, all three results also show as exact. 转换为Python的任意精度整数形式后,所有三个结果也显示为精确。

>>> hex(int(x19))
'0xb9f00a484ac42800000000000'
>>> hex(int(mp19))
'0xb9f00a484ac42800000000000'
>>> hex(int(gp19))
'0xb9f00a484ac42800000000000'

So (at least one) Linux math library, mpmath , and gmpy2.mpfr agree. 因此(至少一个)Linux数学库mpmathgmpy2.mpfr同意。

Disclaimer: I maintain gmpy2 and have contributed to mpmath in the past. 免责声明:我维护gmpy2并在过去为mpmath做出了贡献。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM