我需要一种方法来计算Python中长整数的第n个根。
我尝试了pow(m, 1.0/n)
,但它不起作用:
OverflowError:long int太大而无法转换为float
有什么想法吗?
长整数我的意思是真正的长整数,如:
11968003966030964356885611480383408833172346450467339251 196093144141045683463085291115677488411620264826942334897996389 485046262847265769280883237649461122479734279424416861834396522 819159219215308460065265520143082728303864638821979329804885526 557893649662037092457130509980883789368448042961108430809620626 059287437887495827369474189818588006905358793385574832590121472 680866521970802708379837148646191567765584039175249171110593159 305029014037881475265618958103073425958633163441030267478942720 703134493880117805010891574606323700178176718412858948243785754 898788359757528163558061136758276299059029113119763557411729353 915848889261125855717014320045292143759177464380434854573300054 940683350937992500211758727939459249163046465047204851616590276 724564411037216844005877918224201569391107769029955591465502737 961776799311859881060956465198859727495735498887960494256488224 613682478900505821893815926193600121890632
答案 0 :(得分:26)
如果这是一个非常大的数字。您可以使用二进制搜索。
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
例如:
>>> 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
>>>
答案 1 :(得分:16)
Gmpy是一个C编码的Python扩展模块,它包装了GMP库,为Python代码提供了快速的多精度算法(整数,有理数和浮点数),随机数生成,高级数理论函数等等。
包含root
功能:
x.root(n):返回一个2元素的元组(y,m),这样y就是 (可能被截断)x的第n个根; m,一个普通的Python int, 如果根是精确的(x == y ** n)则为1,否则为0. n必须是普通的 Python int,&gt; = 0。
例如,第20根:
>>> import gmpy
>>> i0=11968003966030964356885611480383408833172346450467339251
>>> m0=gmpy.mpz(i0)
>>> m0
mpz(11968003966030964356885611480383408833172346450467339251L)
>>> m0.root(20)
(mpz(567), 0)
答案 2 :(得分:7)
如果您正在寻找标准的东西,快速写入高精度。我会使用十进制并将精度(getcontext()。prec)调整到至少x的长度。
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)
x是立方数22873918786185635329056863961725521583023133411 451452349318109627653540670761962215971994403670045614485973722724603798 107719978813658857014190047742680490088532895666963698551709978502745901 704433723567548799463129652706705873694274209728785041817619032774248488 2965377218610139128882473918261696612098418
答案 3 :(得分:5)
你可以通过避免使用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)
Norm 0.626754999161
Alt 0.566340923309
答案 4 :(得分:3)
哦,对于数字 大,你会使用十进制模块。
ns:您的数字为字符串
ns = "11968003966030964356885611480383408833172346450467339251196093144141045683463085291115677488411620264826942334897996389485046262847265769280883237649461122479734279424416861834396522819159219215308460065265520143082728303864638821979329804885526557893649662037092457130509980883789368448042961108430809620626059287437887495827369474189818588006905358793385574832590121472680866521970802708379837148646191567765584039175249171110593159305029014037881475265618958103073425958633163441030267478942720703134493880117805010891574606323700178176718412858948243785754898788359757528163558061136758276299059029113119763557411729353915848889261125855717014320045292143759177464380434854573300054940683350937992500211758727939459249163046465047204851616590276724564411037216844005877918224201569391107769029955591465502737961776799311859881060956465198859727495735498887960494256488224613682478900505821893815926193600121890632"
from decimal import Decimal
d = Decimal(ns)
one_third = Decimal("0.3333333333333333")
print d ** one_third
,答案是:2.287391878618402702753613056E + 305
TZ指出这不准确......他是对的。这是我的考试。from decimal import Decimal
def nth_root(num_decimal, n_integer):
exponent = Decimal("1.0") / Decimal(n_integer)
return num_decimal ** exponent
def test():
ns = "11968003966030964356885611480383408833172346450467339251196093144141045683463085291115677488411620264826942334897996389485046262847265769280883237649461122479734279424416861834396522819159219215308460065265520143082728303864638821979329804885526557893649662037092457130509980883789368448042961108430809620626059287437887495827369474189818588006905358793385574832590121472680866521970802708379837148646191567765584039175249171110593159305029014037881475265618958103073425958633163441030267478942720703134493880117805010891574606323700178176718412858948243785754898788359757528163558061136758276299059029113119763557411729353915848889261125855717014320045292143759177464380434854573300054940683350937992500211758727939459249163046465047204851616590276724564411037216844005877918224201569391107769029955591465502737961776799311859881060956465198859727495735498887960494256488224613682478900505821893815926193600121890632"
nd = Decimal(ns)
cube_root = nth_root(nd, 3)
print (cube_root ** Decimal("3.0")) - nd
if __name__ == "__main__":
test()
关闭大约10 ** 891
答案 5 :(得分:2)
可能是为了你的好奇心:
http://en.wikipedia.org/wiki/Hensel_Lifting
这可能是Maple用来实际找到大数字的第n个根的技术。
提出x^n - 11968003.... = 0 mod p
的事实,并从那里开始......
答案 6 :(得分:1)
在旧版本的Python中,1/3
等于0.在Python 3.0中,1/3
等于0.33333333333(并且1//3
等于0)。
因此,要么将代码更改为使用1/3.0
,要么切换到Python 3.0。
答案 7 :(得分:1)
我提出了自己的答案,这需要@Mahmoud Kassem的想法,简化代码,并使其更具可重用性:
def cube_root(x):
return decimal.Decimal(x) ** (decimal.Decimal(1) / decimal.Decimal(3))
我在Python 3.5.1和Python 2.7.8中进行了测试,它似乎运行良好。
结果将包含运行函数的十进制上下文指定的位数,默认情况下为28位小数。根据{{1}}模块中power
功能的文档,&#34; The result is well-defined but only “almost always correctly-rounded”.&#34;。如果您需要更准确的结果,可以按如下方式完成:
decimal
答案 8 :(得分:-1)
尝试将指数转换为浮点数,因为Python中/的默认行为是整数除法
<磷>氮**(1 /浮子(3))答案 9 :(得分:-3)
好吧,如果你不是特别担心精确度,你可以把它转换为刺痛,砍掉一些数字,使用指数函数,然后将结果乘以你切断多少的根。
E.g。 32123大约等于32 * 1000,立方根大约等于立方根32 *立方根1000.后者可以通过将0的数除以3来计算。
这样就无需使用扩展模块。