这里主要是要考虑效率问题,在数据规模较大时,如果不考虑算法优化,效率将会非常差。
import time
# 将特殊质数2事先放在列表中
t = [2]
t0 = time.time()
count = 1
# 去掉所有偶数,从3开始迭代,步进为2
for x in range(3, 100000, 2):
# 所有大于10的质数中,个位数只有1、3、7、9,大于5且以5结尾的整数能被5整除,这里首先过滤掉大于5且以5结尾的整数
if x > 5 and x % 10 == 5:
continue
# 除去2之外,质数的因子中肯定是没有2的,这里去掉所有被除数中的偶数
# 一个整数的前后对应的两个因子的乘积等于这个整数,所以一个整数如果平方根之前有一个因子,那平方根之后肯定有一个对应的因子,中间是平方根
# 这里使用平方根极大减小了数据规模,以及减少了大量迭代次数
for i in range(3, int(x ** 0.5) + 1, 2):
if x % i == 0:
break
# 要格外注意一下这里的else语句的执行逻辑
# 没有进入for循环、以及for循环正常结束都会执行else语句,如果被break中断,else不会执行
else:
count += 1
t.append(x)
# print(t)
print('花费时间: {}'.format(time.time() - t0))
print('质数个数: {}'.format(count))
print('质数个数: {}'.format(len(t)))
# 花费时间: 0.20165777206420898
# 质数个数: 9592
# 质数个数: 9592
为什么可以只考虑平方根之前的部分,上面的备注中已经做了说明,这里以100为例解剖一下:
for i in range(2, 100):
if not 100 % i:
print(i)
2
4
5
10
20
25
50
100 = 2 x 50
100 = 4 x 25
100 = 5 x 20
100 = 10 x 10
这样很容易看出,在平方根10之前,如果100有一个因子,那么平方根后面一定有一个对应的因子,而平方根`10x10`是临界点。所以被除数可以从平方根处砍掉后面的部分。
由于相差一个指数,一个整数的平方根通常都比自身小很多,数值越大,相差越大。比如100比10大90,10000比100大9900,这样看就发现数据量减少了不止一星半点。
关于for循环中else语句的执行逻辑,简单敲一下就清晰了:
# 没有进入for循环会执行else语句
for i in range(3,2):
print('a')
else:
print('b')
# b
# for循环正常结束会执行else语句
for i in range(3,4):
print('a')
else:
print('b')
# a
# b
# for循环如果被break中断,else语句不会执行
for i in range(3,5):
print('a')
break
else:
print('b')
# a
参考:
https://docs.python.org/3/reference/compound_stmts.html#the-for-statement
https://www.cnblogs.com/dspace/p/6622799.html