我在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的wolframalpha值不同。 (光头部分是差异)
ln2 = 0.693147180559945 286227 (cpython)
ln2 = 0.693147180559945 3094172321214581 (wolframalpha)
ln2 = 0.693147180559945 309417232121458 (维基百科)
所以我的问题是为什么会有区别?我错过了什么?
答案 0 :(得分:6)
如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')
在英语中,x
是log(2)
的53位精确值,y
是将代码中的十进制字符串转换为64位二进制浮点格式的结果精度它们完全相同。
在当前的现实中,我希望所有编译器现在将文字转换为本机IEEE-754双格式,精度为53位。
无论哪种方式,代码都会确保使用log(2)
的最佳53位近似值。
答案 1 :(得分:4)
直到binary64浮点表示的精度,这些值是相等的:
In [21]: 0.6931471805599453094172321214581 == 0.693147180559945286227
Out[21]: True
如果将最准确的可表示的ln(2)近似值存储到64位浮点数中然后将其打印到那么多位数,那么 0.693147180559945286227
就是你得到的。试图在float中填充更多数字只会将结果四舍五入为相同的值:
In [23]: '%.21f' % 0.6931471805599453094172321214581
Out[23]: '0.693147180559945286227'
至于为什么他们在代码中写了0.693147180559945286227
,你不得不问那些在1993年在Sun写过FDLIBM的人。这段代码来自FDLIBM。
答案 2 :(得分:3)
您可以使用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 *)