我在git(第25行)看_math.c:
#if !defined(HAVE_ACOSH) || !defined(HAVE_ASINH)
static const double ln2 = 6.93147180559945286227E-01;
static const double two_pow_p28 = 268435456.0; /* 2**28 */
Run Code Online (Sandbox Code Playgroud)
我注意到ln2值与ln2的wolframalpha值不同.(光头部分是差异)
ln2 = 0.693147180559945 286227(cpython)
ln2 = 0.693147180559945 3094172321214581(wolframalpha)
ln2 = 0.693147180559945 309417232121458(维基百科)
所以我的问题是为什么会有区别?我错过了什么?
正如user2357112所指出的,此代码来自FDLIBM.这是为IEEE-754机器精心编写的,其中C双精度具有53位精度.它并不真正关心2的实际日志是什么,但关心最好的53位近似值log(2).
要重现预期的53位精确值,17个十进制数字就足够了.
那么为什么他们使用21位小数呢?我的猜测:21位十进制数是保证转换结果正确到64位精度所需的最小值.这可能在当时已经是一个问题,如果一个编译器以某种方式决定的字面转换到奔腾的80位浮点格式(具有精度为64位).
所以他们用足够的十进制数字显示53位结果,这样如果它被转换为具有64位精度的二进制浮点格式,则尾随的11位(= 64-53)将全部为零,从而确保它们是使用他们从一开始就想要的53位值.
>>> import mpmath
>>> x = mpmath.log(2)
>>> x
mpf('0.69314718055994529')
>>> mpmath.mp.prec = 64
>>> y = mpmath.mpf("0.693147180559945286227")
>>> x == y
True
>>> y
mpf('0.693147180559945286227')
Run Code Online (Sandbox Code Playgroud)
在英语中,x是53位精确值log(2),y是将代码中的十进制字符串转换为64位精度的二进制浮点格式的结果.他们是完全相同的.
在当前的现实中,我希望所有编译器现在将文字转换为本机IEEE-754双格式,具有53位精度.
无论哪种方式,代码log(2)都可确保使用最佳的53位近似值.