cpython中的\u math.c中的ln2 const值

2024-09-30 14:20:30 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在查看git中的_math.c(第25行):

#if !defined(HAVE_ACOSH) || !defined(HAVE_ASINH)
static const double ln2 = 6.93147180559945286227E-01;
static const double two_pow_p28 = 268435456.0; /* 2**28 */

我注意到ln2的值和ln2的whatwolframalpha值不同。(秃顶是区别)

ln2=0.693147180559945286227(cpython)

ln2=0.6931471805599453094172321214581(沃尔夫拉马尔法)

ln2=0.693147180559945309417232121458(维基百科)

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


Tags: gitifhavestaticmathdoubletwo区别
3条回答

如user2357112所述,此代码来自FDLIBM。这是为IEEE-754机器精心编写的,其中C双精度有53位。它并不真正关心2的实际日志是什么,而是非常关心log(2)的最佳53位近似值。在

要重现预期的53位精确值,17 decimal digits would have sufficed。在

那么为什么他们用21位小数呢?我的猜测是:21位小数是保证转换后的结果正确到64位精度所需的最小值。如果编译器以某种方式决定将文本转换为Pentium的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')

在英语中,xlog(2)的53位精确值,y是将代码中的十进制字符串转换为精度为64位的二进制浮点格式的结果。它们是一样的。在

在当前的现实中,我希望所有的编译器都能将文本转换成本地的IEEE-754双精度格式,精度为53位。在

无论哪种方式,代码都确保使用log(2)的最佳53位近似值。在

在二进制64浮点表示的精度范围内,这些值相等:

In [21]: 0.6931471805599453094172321214581 == 0.693147180559945286227
Out[21]: True

0.693147180559945286227是将ln(2)最精确的可表示近似值存储到一个64位浮点中,然后将其打印到那么多个数字。尝试在浮点中填充更多的数字只会使结果四舍五入到相同的值:

^{pr2}$

至于他们为什么在代码中写0.693147180559945286227,你得问问1993年在Sun上写FDLIBM的人。这个代码来自FDLIBM。在

Python似乎错了,尽管我不确定这是一个疏忽,或者它有更深的含义。21点的解释似乎合理,但我不明白,为什么他们会给出错误的数字。在

您可以使用More efficient series下的公式自己检查。在Mathematica中,你可以用

log2 = 2*Sum[1/i*(1/3)^i, {i, 1, 70, 2}]

(*
79535292197135923776615186805136682215642574454974413288086/
114745171628462663795273979107442710223059517312975273318225
*)

使用N[log2,30]可以得到正确的数字

^{pr2}$

它支持Wikipedia和W | A的正确性。如果您愿意,您可以对机器精度数字进行相同的计算。在Mathematica中,这通常意味着double。在

logC = Compile[{{z, _Real, 0}},
  2.0*Sum[1/i*((z - 1)/(z + 1))^i, {i, 1, 100, 2}]
]

请注意,这段代码完全编译为普通的迭代,并且不使用一些减少错误的求和方案。所以没有神奇的编译Sum函数。在我的机器上显示:

logC[2]//FullForm
(* 0.6931471805599451` *)

在你指出的数字范围内都是正确的。这有21点建议的精度

$MachinePrecision
(* 15.9546 *)

编辑

正如在注释和答案中指出的,您在_math.c中看到的值可能是53位表示

digits = RealDigits[log2, 2, 53];
N[FromDigits[digits, 2], 21]

(*  0.693147180559945286227 *)

相关问题 更多 >