Python mpmath 不是任意精度?

2 投票
3 回答
3276 浏览
提问于 2025-04-20 08:29

我在继续之前的问题,想用贝内特算法计算斐波那契数。为了处理任意精度的计算,我找到了 mpmath 这个库。不过在计算到某个值的时候,似乎出现了问题。例如,计算第99个斐波那契数时,结果是:

218922995834555891712

但这个结果应该是(参考链接:这里):

218922995834555169026

这是我的代码:

from mpmath import *

def Phi():
    return (1 + sqrt(5)) / 2

def phi():
    return (1 - sqrt(5)) / 2

def F(n):
    return (power(Phi(), n) - power(phi(), n)) / sqrt(5)

start = 99
end = 100

for x in range(start, end):
    print(x, int(F(x)))

3 个回答

3

其实,mpmath的默认精度是15,这个精度我觉得不够,如果你想要得到21位数字的结果的话。

你可以做的一件事就是把精度设置得更高,然后使用mpmath提供的加法、减法等运算功能。

    from mpmath import mp
    mp.dps = 50
    sqrt5 = mp.sqrt(5)
    def Phi():
        return 0.5*mp.fadd(1, sqrt5)

    def phi():
        return 0.5*mp.fsub(1, sqrt5)

    def F(n):
        return mp.fdiv(mp.power(Phi(), n) - mp.power(phi(), n), sqrt5)

    print int(F(99))

这样你就能得到

    218922995834555169026L
4

mpmath 是一个可以进行任意精度数学运算的工具,如果你使用它的任意精度数学模块,而不是默认的设置,它可以做到非常准确。

mpmath 有多个模块可以选择,这些模块会影响结果的准确性和计算速度,你可以根据自己的需求来选择。默认情况下,它使用的是 Python 的浮点数,这就是你之前看到的结果。

如果你调用 mpmath 的 fib( ) 函数,并且把 mp.dps 设置得足够高,你就能得到上面提到的正确答案。

>>> from mpmath import mp
>>> mp.dps = 25
>>> mp.nprint( mp.fib( 99 ), 25 )
218922995834555169026.0
>>> mp.nprint( mpmath.fib( 99 ), 25 )
218922995834555169026.0

但是,如果你不使用 mp 模块,你得到的结果就只能和 Python 的双精度浮点数一样准确。

>>> import mpmath
>>> mpmath.dps = 25
>>> mpmath.nprint( mpmath.fib( 99 ), 25
218922995834555170816.0
3

mpmath 是一个可以进行任意精度计算的工具(精度可以通过 mpmath.mp.dps 来设置),但它的计算结果可能不够准确。例如,mpmath.sqrt(5) 的结果并不准确,因此基于这个结果进行的任何计算也会不准确。

如果想要得到准确的 sqrt(5) 的结果,你需要使用一个支持抽象计算的库,比如 http://sympy.org/

想要准确计算斐波那契数列,最简单的方法可能是使用只进行整数运算的算法。例如:

def fib(n):
  if n < 0:
    raise ValueError

  def fib_rec(n):
    if n == 0:
      return 0, 1
    else:
      a, b = fib_rec(n >> 1)
      c = a * ((b << 1) - a)
      d = b * b + a * a
      if n & 1:
        return d, c + d
      else:
        return c, d

  return fib_rec(n)[0]

撰写回答