完全数
【问题】如果一个正整数的所有因子的和是自身的2倍(也可以描述为:除了自身之外的因子之和正好等于自身),则称之为完全数。
比如: 6, 28 就是前2个完全数。请找出10000以内的所有完全数。
这个定义很容易理解,解法也很明显:从1开始向上搜索,每遇到一个因子,就累加起来。最后看看是不是符合条件。
def is_wan_quan(n):
sum = 0
for i in range(1,n):
if n % i == 0: sum += i
return sum == n
if __name__ == '__main__':
for i in range(10000):
if is_wan_quan(i): print(i)
稍微有点遗憾的是运行速度较慢。
看看有没可以优化的地方。
因子总成对出现的。如果 p 是 n 的因子,必然 q = n // p 也是 n 的因子。
我们只要找到了一半数目的因子,另一半可以计算出来。
所以,不需要从 1 搜索到 n, 只要到 大约 n \sqrt{n} n就够了。
下面的代码就利用这个原理,速度大为提高。
import math
def is_wan_quan(n):
sum = 0
k = round(math.sqrt(n))
if k * k <= n: k +=1
for i in range(1, k):
if n % i == 0:
sum += i
if(n//i != i): sum += n // i
return sum == 2 * n
if __name__ == '__main__':
for i in range(1,10000):
if is_wan_quan(i):
print(i)
这里对开方的处理要小心。因为计算表示小数时是不精确的。一个正好可以开方的数字,其结果也可能会有点误差。这里开方出来的数字再平方回去就是为了消除这种误差的影响。
如果对这个问题不理会,甩锅给 python,直接让它比较整数和浮点数。
import math
def is_wan_quan(n):
t = math.sqrt(n)
sum = 0
i = 1
while i<=t:
if n % i == 0:
j = n // i
sum += i + (j if j > i else 0)
i += 1
return sum == 2 * n
if __name__ == '__main__':
for i in range(1,10000):
if is_wan_quan(i): print(i)
似乎对这个问题也没多大影响。
但浮点数不精确的这个坑是真实存在,看下面的例子:
print(0.1 + 0.2)
print(0.1 + 0.2 == 0.3)
结果居然是 False !!!