在cpython中的_math.c中的ln2 const值

Mat*_*roh 3 python cpython

我在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(维基百科)

所以我的问题是为什么会有区别?我错过了什么?

Tim*_*ers 6

正如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位近似值.

  • 除了FDLIBM无意处理"可变精度"之外:它在整个过程中都经过仔细而巧妙的编写,以便在符合IEEE-754标准的算法的盒子上提供高质量的结果.这会影响所有内容,例如,使用的常数,多项式和有理逼近中使用的项数,以及所使用的精确操作顺序.在它的代码中有_many_个地方依赖于精确到53位的精度,并且算术上最好的舍入.变量精度需要不同的_algorithms_,而不仅仅是不同的常量. (4认同)