如何计算一个非常大的整数的第n个根

PiX*_*PiX 28 python math nth-root

我需要一种方法来计算Python中长整数的第n个根.

我试过了pow(m, 1.0/n),但它不起作用:

OverflowError:long int太大而无法转换为float

有任何想法吗?

通过长整数,我的意思是真正的长整数,如:

11968003966030964356885611480383408833172346450467339251 196093144141045683463085291115677488411620264826942334897996389 485046262847265769280883237649461122479734279424416861834396522 819159219215308460065265520143082728303864638821979329804885526 557893649662037092457130509980883789368448042961108430809620626 059287437887495827369474189818588006905358793385574832590121472 680866521970802708379837148646191567765584039175249171110593159 305029014037881475265618958103073425958633163441030267478942720 703134493880117805010891574606323700178176718412858948243785754 898788359757528163558061136758276299059029113119763557411729353 915848889261125855717014320045292143759177464380434854573300054 940683350937992500211758727939459249163046465047204851616590276 724564411037216844005877918224201569391107769029955591465502737961776799311859881060956465198859727495735498887960494256488224 613682478900505821893815926193600121890632

Mar*_*rot 27

如果这是一个非常大的数字.您可以使用二进制搜索.

def find_invpow(x,n):
    """Finds the integer component of the n'th root of x,
    an integer such that y ** n <= x < (y + 1) ** n.
    """
    high = 1
    while high ** n <= x:
        high *= 2
    low = high/2
    while low < high:
        mid = (low + high) // 2
        if low < mid and mid**n < x:
            low = mid
        elif high > mid and mid**n > x:
            high = mid
        else:
            return mid
    return mid + 1
Run Code Online (Sandbox Code Playgroud)

例如:

>>> x = 237734537465873465
>>> n = 5
>>> y = find_invpow(x,n)
>>> y
2986
>>> y**n <= x <= (y+1)**n
True
>>>
>>> x = 119680039660309643568856114803834088331723464504673392511960931441>
>>> n = 45
>>> y = find_invpow(x,n)
>>> y
227661383982863143360L
>>> y**n <= x < (y+1)**n
True
>>> find_invpow(y**n,n) == y
True
>>>
Run Code Online (Sandbox Code Playgroud)

  • 对于&gt;〜10 ** 1000的数字仍然会失败。将`mid =(low + high)// 2`更改为`mid = int((low + high)// 2)+ 1`将解决此问题。 (2认同)
  • 投反对票,因为它有错误。我尝试了 find_invpow(64, 3) 并得到了 3,即使结果应该是 4。 (2认同)

gim*_*mel 16

Gmpy是一个C编码的Python扩展模块,它包装GMP库,为Python代码提供快速多精度算法(整数,有理数和浮点数),随机数生成,高级数理论函数等.

包括一个root功能:

x.root(n):返回一个2元素元组(y,m),这样y就是x的第n个根(可能被截断); m,一个普通的Python int,如果根是精确的,则为1(x == y**n),否则为0. n必须是普通的Python int,> = 0.

例如,20根:

>>> import gmpy
>>> i0=11968003966030964356885611480383408833172346450467339251 
>>> m0=gmpy.mpz(i0)
>>> m0
mpz(11968003966030964356885611480383408833172346450467339251L)
>>> m0.root(20)
(mpz(567), 0)
Run Code Online (Sandbox Code Playgroud)

  • @Zelphir gmpy2 有 `gmpy2.iroot` 来计算整数根。 (2认同)

小智 7

如果您正在寻找标准的东西,快速写入高精度.我会使用十进制并将精度(getcontext().prec)调整到至少x的长度.

代码(Python 3.0)

from decimal import *

x =   '11968003966030964356885611480383408833172346450467339251\
196093144141045683463085291115677488411620264826942334897996389\
485046262847265769280883237649461122479734279424416861834396522\
819159219215308460065265520143082728303864638821979329804885526\
557893649662037092457130509980883789368448042961108430809620626\
059287437887495827369474189818588006905358793385574832590121472\
680866521970802708379837148646191567765584039175249171110593159\
305029014037881475265618958103073425958633163441030267478942720\
703134493880117805010891574606323700178176718412858948243785754\
898788359757528163558061136758276299059029113119763557411729353\
915848889261125855717014320045292143759177464380434854573300054\
940683350937992500211758727939459249163046465047204851616590276\
724564411037216844005877918224201569391107769029955591465502737\
961776799311859881060956465198859727495735498887960494256488224\
613682478900505821893815926193600121890632'

minprec = 27
if len(x) > minprec: getcontext().prec = len(x)
else:                getcontext().prec = minprec

x = Decimal(x)
power = Decimal(1)/Decimal(3)

answer = x**power
ranswer = answer.quantize(Decimal('1.'), rounding=ROUND_UP)

diff = x - ranswer**Decimal(3)
if diff == Decimal(0):
    print("x is the cubic number of", ranswer)
else:
    print("x has a cubic root of ", answer)
Run Code Online (Sandbox Code Playgroud)

回答

x是22873918786185635329056863961725521583023133411 451452349318109627653540670761962215971994403670045614485973722724603798 107719978813658857014190047742680490088532895666963698551709978502745901 704433723567548799463129652706705873694274209728785041817619032774248488 2965377218610139128882473918261696612098418立方数


Bri*_*ian 6

你可以通过避免使用while循环来支持将低值设置为10**(len(str(x))/ n)和从高到低*10来使其运行得更快.可能更好的是替换len(str(x) ))按位长度并使用位移.根据我的测试,我估计从第一次开始加速5%,从第二开始加速25%.如果整数足够大,这可能很重要(并且加速可能会有所不同).如果不仔细测试,请不要相信我的代码.我做了一些基本测试,但可能错过了边缘情况.此外,这些加速比例随所选数量而变化.

如果您使用的实际数据比您在此处发布的数据大得多,则此更改可能是值得的.

from timeit import Timer

def find_invpow(x,n):
    """Finds the integer component of the n'th root of x,
    an integer such that y ** n <= x < (y + 1) ** n.
    """
    high = 1
    while high ** n < x:
        high *= 2
    low = high/2
    while low < high:
        mid = (low + high) // 2
        if low < mid and mid**n < x:
            low = mid
        elif high > mid and mid**n > x:
            high = mid
        else:
            return mid
    return mid + 1

def find_invpowAlt(x,n):
    """Finds the integer component of the n'th root of x,
    an integer such that y ** n <= x < (y + 1) ** n.
    """
    low = 10 ** (len(str(x)) / n)
    high = low * 10

    while low < high:
        mid = (low + high) // 2
        if low < mid and mid**n < x:
            low = mid
        elif high > mid and mid**n > x:
            high = mid
        else:
            return mid
    return mid + 1

x = 237734537465873465
n = 5
tests = 10000

print "Norm", Timer('find_invpow(x,n)', 'from __main__ import find_invpow, x,n').timeit(number=tests)
print "Alt", Timer('find_invpowAlt(x,n)', 'from __main__ import find_invpowAlt, x,n').timeit(number=tests)
Run Code Online (Sandbox Code Playgroud)

规范0.626754999161

Alt 0.566340923309