【问题标题】:Using the sqrt function of math module for long numbers in python在python中使用math模块的sqrt函数处理长数
【发布时间】:2015-03-24 21:46:50
【问题描述】:

我在 python 中处理 200 位数字。使用 math.sqrt(n) 找到数字的平方根时,我得到了错误的答案。

In[1]: n=9999999999999999999999999999999999999999999999999999999999999999999999
       999999999999999999999999998292000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000726067

In[2]: x=int(math.sqrt(n))

In[3]: x
Out[1]: 10000000000000000159028911097599180468360808563945281389781327
        557747838772170381060813469985856815104L

In[4]: x*x
Out[2]: 1000000000000000031805782219519836346574107361670094060730052612580
        0264077231077619856175974095677538298443892851483731336069235827852
        3336313169161345893842466001164011496325176947445331439002442530816L

In[5]: math.sqrt(n)
Out[3]: 1e+100

x 的值比预期的要大,因为 x*x(201 位)大于 n(200 位)。这里发生了什么?有什么概念我在这里弄错了吗?我还能如何找到非常大的数字的根?

【问题讨论】:

  • 把x=int(math.sqrt(n))改成x=math.sqrt(n)试试看
  • 它以指数形式给出与 1e+100 相同的答案。
  • math.sqrt() 返回一个受 IEEE 754 算法约束的浮点值,而不是 bignum。
  • 要处理如此大的数字,您应该查看标准的decimal 模块,或第3 方mpmath 模块。或者,如果您只想要一个整数平方根,您可以使用Babylonian method 编写一个,也就是英雄方法,这是牛顿方法的一个特例。

标签: python long-integer


【解决方案1】:

math.sqrt 返回 IEEE-754 64 位结果,大约为 17 位。还有其他库可以处理高精度值。除了上面提到的decimal 和mpmath 库之外,我还维护了gmpy2 库(https://code.google.com/p/gmpy/)。

>>> import gmpy2
>>> n=gmpy2.mpz(99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999982920000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000726067)
>>> gmpy2.get_context().precision=2048
>>> x=gmpy2.sqrt(n)
>>> x*x
mpfr('99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999982920000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000726067.0',2048)
>>>

gmpy2 库还可以返回整数平方根 (isqrt) 或快速检查整数是否为精确平方 (is_square)。

【讨论】:

    【解决方案2】:

    这是一个整数平方根程序,它使用了我不久前编写的 Hero 方法。对于初始近似,它使用输入值位长度的一半,因此它开始很快收敛。但是,我还没有确定它在 Python 中是否比仅使用更简单的初始近似值更快。 :)

    #! /usr/bin/env python
    
    ''' Long integer square roots. Newton's method.
    
        Written by PM 2Ring. Adapted from C to Python 2008.10.19
    '''
    
    import sys
    
    def root(m):
        # Get initial approximation
        n, a, k = m, 1, 0
        while n > a:
            n >>= 1
            a <<= 1
            k += 1
            #print k, ':', n, a
    
        # Go back one step & average
        a = n + (a>>2)
        #print a
    
        # Apply Newton's method
        while k:
            a = (a + m // a) >> 1
            k >>= 1
            #print k, ':', a
        return a
    
    def main():
        m = len(sys.argv) > 1 and int(sys.argv[1]) or 2*10L**100
        print "The Square Root of", m
        print root(m)
    
    if __name__ == '__main__':
        main()
    

    【讨论】:

      【解决方案3】:

      使用the decimal module:

      import decimal
      D = decimal.Decimal
      n = D(99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999982920000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000726067)
      
      with decimal.localcontext() as ctx:
          ctx.prec = 300
          x = n.sqrt()
          print(x)
          print(x*x)
          print(n-x*x)
      

      产量

      9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999145.99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999983754999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999998612677
      
      99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999982920000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000726067.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
      
      0E-100
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-02-24
        • 2012-03-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-02-16
        • 2022-07-13
        相关资源
        最近更新 更多