我想找到小于或等于n的k次方根的最大整数。我已经尝试过
int(n**(1/k))
但对于n=125,k=3,这给出了错误的答案!我碰巧知道5的三次方是125。
>>> int(125**(1/3))
4
哪个算法更好?
背景:在2011年,这个小失误让我错失了击败谷歌代码竞赛难题Expensive Dinner的机会。
我想找到小于或等于n的k次方根的最大整数。我已经尝试过
int(n**(1/k))
但对于n=125,k=3,这给出了错误的答案!我碰巧知道5的三次方是125。
>>> int(125**(1/3))
4
哪个算法更好?
背景:在2011年,这个小失误让我错失了击败谷歌代码竞赛难题Expensive Dinner的机会。
怎么样:
def nth_root(val, n):
ret = int(val**(1./n))
return ret + 1 if (ret + 1) ** n == val else ret
print nth_root(124, 3)
print nth_root(125, 3)
print nth_root(126, 3)
print nth_root(1, 100)
这里,val
和n
都应该是正整数。这使得return
表达式完全依赖于整数算术,消除了任何舍入误差的可能性。
请注意,只有当val**(1./n)
相对较小时,才能保证精度。一旦该表达式的结果偏离真实答案超过1
,该方法将不再给出正确答案(它会给出与您原始版本相同的近似答案)。
我仍然想知道为什么
int(125**(1/3))
等于4
In [1]: '%.20f' % 125**(1./3)
Out[1]: '4.99999999999999911182'
int()
将其截断为4
。
<=
代替==
,因为测试浮点数的相等性通常是很棘手的。 - unutbu125**(1./3)
。你应该会得到类似于4.999999999999999
的结果,而不是5
。使用 int
会将其向下取整为 4
。 - unutbu4 ** (1./3)
和许多其他输入上失败,而我答案中的方法不会。 - NPE一种解决方案是将答案首先夹在lo和hi之间,通过反复将hi乘以2直到n在lo和hi之间,然后使用二分查找来计算准确答案:
def iroot(k, n):
hi = 1
while pow(hi, k) < n:
hi *= 2
lo = hi // 2
while hi - lo > 1:
mid = (lo + hi) // 2
midToK = pow(mid, k)
if midToK < n:
lo = mid
elif n < midToK:
hi = mid
else:
return mid
if pow(hi, k) == n:
return hi
else:
return lo
另一种解决方案使用牛顿迭代法,在整数上可以完美地工作:
def iroot(k, n):
u, s = n, n+1
while u < s:
s = u
t = (k-1) * s + n // pow(s, k-1)
u = t // k
return s
在我严重受挫之后,我采取了谨慎的解决方案:
def nth_root(N,k):
"""Return greatest integer x such that x**k <= N"""
x = int(N**(1/k))
while (x+1)**k <= N:
x += 1
while x**k > N:
x -= 1
return x
N
太大无法转换为浮点数,则N**(1./k)
会导致计算错误。对于足够小的N
来说,N**(1./k)
是接近准确的,所以调整时间不会太长。如果你对处理大数感兴趣,其中将整数转换为浮点数会损失过多精度,那么进行几步牛顿迭代法可以获得精确结果。 - Daniel Fischer125 ** (1 / float(3))
pow(125, 1 / float(3))
这是使用牛顿-拉弗森方法的Lua代码:
> function nthroot (x, n) local r = 1; for i = 1, 16 do r = (((n - 1) * r) + x / (r ^ (n - 1))) / n end return r end
> return nthroot(125,3)
5
>
Python版本
>>> def nthroot (x, n):
... r = 1
... for i in range(16):
... r = (((n - 1) * r) + x / (r ** (n - 1))) / n
... return r
...
>>> nthroot(125,3)
5
>>>
range(32)
已经足够了。 - Doug Currieimport math
def power_floor(n, k):
return int(math.exp(1.0 / k * math.log(n)))
def nth_root(val, n):
ret = int(val**(1./n))
return ret + 1 if (ret + 1) ** n == val else ret
cases = [
(124, 3),
(125, 3),
(126, 3),
(1, 100),
]
for n, k in cases:
print "{0:d} vs {1:d}".format(nth_root(n, k), power_floor(n, k))
4 vs 4
5 vs 5
5 vs 5
1 vs 1
def nth_root(n, k):
x = n**(1./k)
y = int(x)
return y + 1 if y != x else y
def nthrootofm(a,n):
a= pow(a,(1/n))
return 'rounded:{},'.format(round(a))
a=125
n=3
q=nthrootofm(a,n)
print(q)
刚刚使用了格式化字符串,也许这会有所帮助。
def rtn (x):
return int (x + 0.5)
>>> rtn (125 ** (1/3))
5
rtn(4 ** (1./3))
是 2,但是 2**3 > 4
。 - unutbu在开始之前,请先执行以下操作:
from __future__ import division
然后运行上述任何一种技术,以获得您的结果。
125**(1/3)
->4.999999999999999
- wjandrea