gmpy2 log2在16位数后不准确

时间:2015-10-10 21:34:24

标签: python math gmpy

在gmpy2中使用log2()时,16位数后似乎不准确。它看起来在15位数下正常工作但在那之后使用mpz(mpfr(2)** mpfr(x))的答案是不正确的。我需要改变精度吗?我认为python本身最多可以准确53位。

另外,gmpy2中有没有办法在10和2之外的基数中使用对数运算?例如,基数为8或16。

1 个答案:

答案 0 :(得分:1)

标准Python浮点类型精确到53位,大约是16位十进制数。 gmpy2使用53位的默认精度。如果您想要更准确的结果,则需要提高精度。

>>> import gmpy2
>>> from gmpy2 import mpz,mpfr,log2
>>> a=12345678901234567890
>>> gmpy2.get_context().precision=70
>>> mpz(2**log2(a))
mpz(12345678901234567890L)

要计算不同的对数,只需使用

>>> gmpy2.log(x)/gmpy2.log(base)

<强>更新

通常无法从一系列浮点计算中恢复精确的整数结果。根据实际计算,您可以提高精度,直到足够接近&#34;。

让我们来看看精确度的影响。请注意a长度为57位,因此不能用53位浮点精度来精确表示。

>>> a=123543221556677776
>>> a.bit_length()
57
>>> gmpy2.get_context().precision=53
>>> mpfr(a);2**log2(a)
mpfr('1.2354322155667778e+17')
mpfr('1.2354322155667752e+17')

由于将二进制浮点数转换为十进制可能会引入转换错误,让我们以二进制形式查看结果。

>>> mpfr(a).digits(2);(2**log2(a)).digits(2)
('11011011011101001111001111100101101001011000011001001', 57, 53)
('11011011011101001111001111100101101001011000010111001', 57, 53)

让我们尝试将精度提高到57位。

>>> gmpy2.get_context().precision=57
>>> mpfr(a).digits(2);(2**log2(a)).digits(2)
('110110110111010011110011111001011010010110000110010010000', 57, 57)
('110110110111010011110011111001011010010110000110010011000', 57, 57)

请注意更多位是正确的,但仍然存在错误。让我们尝试64位。

>>> gmpy2.get_context().precision=64
>>> mpfr(a);2**log2(a)
mpfr('123543221556677776.0',64)
mpfr('123543221556677775.953',64)
>>> mpfr(a).digits(2);(2**log2(a)).digits(2)
('1101101101110100111100111110010110100101100001100100100000000000', 57, 64)
('1101101101110100111100111110010110100101100001100100011111111010', 57, 64)

大量的尾随1大致相当于十进制的9位。

一旦你得到&#34;足够接近&#34;,你就可以转换成一个整数,将结果四舍五入到预期值。

为什么57位不足? gmpy2使用的MPFR库执行正确的舍入。还有一个小错误。让我们使用正确舍入值正上方和下方的浮点值来查看结果。

>>> gmpy2.get_context().precision=57
>>> b=log2(a)
>>> 2**gmpy2.next_below(b);2**log2(a);2**gmpy2.next_above(b)
mpfr('123543221556677746.0',57)
mpfr('123543221556677784.0',57)
mpfr('123543221556677822.0',57)

请注意,b中的一小部分更改会导致2**b发生更大的变化。

更新2

浮点算术只是实数数学性质的近似值。有些数字是合理的(它们可以写成一小部分)但大多数数字都是不合理的(它们永远不能完全写成一小部分)。浮点运算实际上使用了对数的有理逼近。

我已经跳过了以下的一些细节 - 我假设所有数字都介于0和1之间。

对于二进制浮点(大多数计算机使用的),有理逼近的分母必须是2的幂。1/21/4之类的数字可以精确表示。十进制浮点使用具有10的幂的分母的有理逼近。数字如1/2,&#39; 1/4&#39;,&#39; 1/5&#39;和{{ 1}}都可以完全表示。两者都不能完全代表1/20。浮点运算的base-6实现可以完全代表1/31/2但不代表1/3。特定格式的精度仅指定分子的最大大小。总会有一些有理数的数字无法用给定的基数完全表示。

由于无理数不能写为有理数,因此不能用给定的数字来精确表示。由于对数和指数函数几乎总是导致无理值,因此计算几乎从不精确。通过提高精度,您通常可以得到足够的接近&#34;但你永远无法准确。

有些节目有效1/10 - 他们记得symbolicallya,当你log2(n)时,会返回2**a的确切值。请参阅SymPy