cpython _math.c 中的 ln2 const 值
ln2 const value in _math.c in 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 */
我注意到 ln2 值与 ln2 的 what wolframalpha 值不同。 (光头部分是有区别的)
ln2 = 0.693147180559945286227 (cpython)
ln2 = 0.6931471805599453094172321214581 (wolframalpha)
ln2 = 0.693147180559945309417232121458(维基百科)
所以我的问题是为什么会有差异?我错过了什么?
Python 似乎是错误的,虽然我不确定这是一个疏忽还是有更深的含义。 BlackJack的解释似乎有道理,但我不明白,为什么他们会给出错误的额外数字。
您可以使用 More efficient series 下的公式自行检查。在 Mathematica 中,您最多可以使用
计算 70(35 个加数)
log2 = 2*Sum[1/i*(1/3)^i, {i, 1, 70, 2}]
(*
79535292197135923776615186805136682215642574454974413288086/
114745171628462663795273979107442710223059517312975273318225
*)
使用 N[log2,30]
你得到正确的数字
0.693147180559945309417232121458
支持维基百科和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` *)
并且直到你指出的数字都是正确的。这具有 BlackJack
建议的精度
$MachinePrecision
(* 15.9546 *)
编辑
正如评论和答案中所指出的,您在 _math.c
中看到的值可能是 53 位表示
digits = RealDigits[log2, 2, 53];
N[FromDigits[digits, 2], 21]
(* 0.693147180559945286227 *)
根据 binary64 浮点表示的精度,这些值是相等的:
In [21]: 0.6931471805599453094172321214581 == 0.693147180559945286227
Out[21]: True
0.693147180559945286227
是将 ln(2) 最准确的可表示近似值存储到 64 位浮点数中,然后将其打印成那么多数字时得到的结果。尝试在浮点数中填充更多数字只会将结果四舍五入为相同的值:
In [23]: '%.21f' % 0.6931471805599453094172321214581
Out[23]: '0.693147180559945286227'
至于代码里为什么要写0.693147180559945286227
,你得问问1993年Sun写FDLIBM的人了,这个代码来自FDLIBM
如 user2357112 所述,此代码来自 FDLIBM。这是为 IEEE-754 机器精心编写的,其中 C double 具有 53 位精度。它并不真正关心 2 的实际对数是多少,而是非常关心 log(2)
.
的最佳 53 位近似值
要重现预期的 53 位精确值,17 decimal digits would have sufficed。
那么为什么他们改用 21 位十进制数字呢?我的猜测:21 位十进制数字是保证转换结果正确到 64 位精度所需的最少数字。如果编译器以某种方式决定将文字转换为 Pentium 的 80 位浮点格式(具有 64 位精度),那么 可能 在当时是个问题。
因此他们显示了具有足够十进制数字的 53 位结果,以便 if 它被转换为具有 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')
英文中,x
是log(2)
的53位精确值,y
是将代码中的十进制字符串转换为二进制浮点格式的结果64 位精度。它们是相同的。
在当前的现实中,我希望所有编译器现在都将文字转换为本机 IEEE-754 双精度格式,精度为 53 位。
无论哪种方式,代码都会确保使用 log(2)
的最佳 53 位近似值。
我正在 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 */
我注意到 ln2 值与 ln2 的 what wolframalpha 值不同。 (光头部分是有区别的)
ln2 = 0.693147180559945286227 (cpython)
ln2 = 0.6931471805599453094172321214581 (wolframalpha)
ln2 = 0.693147180559945309417232121458(维基百科)
所以我的问题是为什么会有差异?我错过了什么?
Python 似乎是错误的,虽然我不确定这是一个疏忽还是有更深的含义。 BlackJack的解释似乎有道理,但我不明白,为什么他们会给出错误的额外数字。
您可以使用 More efficient series 下的公式自行检查。在 Mathematica 中,您最多可以使用
计算 70(35 个加数)log2 = 2*Sum[1/i*(1/3)^i, {i, 1, 70, 2}]
(*
79535292197135923776615186805136682215642574454974413288086/
114745171628462663795273979107442710223059517312975273318225
*)
使用 N[log2,30]
你得到正确的数字
0.693147180559945309417232121458
支持维基百科和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` *)
并且直到你指出的数字都是正确的。这具有 BlackJack
建议的精度$MachinePrecision
(* 15.9546 *)
编辑
正如评论和答案中所指出的,您在 _math.c
中看到的值可能是 53 位表示
digits = RealDigits[log2, 2, 53];
N[FromDigits[digits, 2], 21]
(* 0.693147180559945286227 *)
根据 binary64 浮点表示的精度,这些值是相等的:
In [21]: 0.6931471805599453094172321214581 == 0.693147180559945286227
Out[21]: True
0.693147180559945286227
是将 ln(2) 最准确的可表示近似值存储到 64 位浮点数中,然后将其打印成那么多数字时得到的结果。尝试在浮点数中填充更多数字只会将结果四舍五入为相同的值:
In [23]: '%.21f' % 0.6931471805599453094172321214581
Out[23]: '0.693147180559945286227'
至于代码里为什么要写0.693147180559945286227
,你得问问1993年Sun写FDLIBM的人了,这个代码来自FDLIBM
如 user2357112 所述,此代码来自 FDLIBM。这是为 IEEE-754 机器精心编写的,其中 C double 具有 53 位精度。它并不真正关心 2 的实际对数是多少,而是非常关心 log(2)
.
要重现预期的 53 位精确值,17 decimal digits would have sufficed。
那么为什么他们改用 21 位十进制数字呢?我的猜测:21 位十进制数字是保证转换结果正确到 64 位精度所需的最少数字。如果编译器以某种方式决定将文字转换为 Pentium 的 80 位浮点格式(具有 64 位精度),那么 可能 在当时是个问题。
因此他们显示了具有足够十进制数字的 53 位结果,以便 if 它被转换为具有 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')
英文中,x
是log(2)
的53位精确值,y
是将代码中的十进制字符串转换为二进制浮点格式的结果64 位精度。它们是相同的。
在当前的现实中,我希望所有编译器现在都将文字转换为本机 IEEE-754 双精度格式,精度为 53 位。
无论哪种方式,代码都会确保使用 log(2)
的最佳 53 位近似值。