Project Euler 80: Square root digital expansion
众所周知如果一个整数的平方根不是一个整数,那么这个平方根就是一个无理数,这种平方根的小数表示是无限不循环的。二的平方根是\(1.41421356237309504880...\),它的前一百位数字的和是475。对于前一百个自然数,如果它的平方根是无理数,求这些无理数的小数表示的前一百之和的和。
分析:计算平方根的方法有很多,如经典的牛顿迭代法,但这些方法都会使用浮点数,从而容易出现近似误差的问题,在求小数表示的数位之和时容易出现错误。经过查阅资料,在这篇论文中我发现一个非常简单易懂的计算任意精度的平方根的方法,这种方法虽然收敛速度要慢于牛顿迭代法,但最大的优点是只需要通过整数的加减就可以得到答案,从而完全避免浮点误差问题。对算法的具体介绍和背后的原理大家可以参见论文,我这里只简单描述以下算法的实现步骤:
- 要求非完全平方数\(n\)的平方根前\(p\)位有效数字之和,则设\(a=5n,b=5\);
- 如果\(a\ge b\),则\(a-b\rightarrow a,b+10\rightarrow b\);
- 如果\(a<b\),则\(100a\rightarrow a\),并在\(b\)的个位数之前加上一个零构成一个新数再赋值给\(b\);
- 如上一直循环,直到\(b\)的位数达到\(p\)位(实际中为了避免误差,会再多求两三位);
- 循环结束后返回\(b\)的前\(p\)位数数位之和,即为题目所求。
对于前一百个自然数中的非完全平方数,依次求其小数表示的前一百个有效数字之和,然后把这些和加总起来,即为题目所求,代码如下:
# time cost = 42.1 ms ± 549 µs
def jarvis_sqrt_sum(n,prec=100):
a,b = 5*n,5
while len(str(b)) <= prec+3:
if a >= b:
a,b = a-b,b+10
else:
a,b = a*100,(b-b%10)*10+b%10
return sum([int(x) for x in str(b)[:prec]])
def main():
numbers = set(range(2,100))-{x**2 for x in range(2,10)}
ans = 0
for i in numbers:
ans += jarvis_sqrt_sum(i)
return ans
除非特别声明,本站文章皆为原创,如需转载请与博主联系,更多精彩内容请参见我的个人博客:https://www.metaquant.org/index.html

浙公网安备 33010602011771号