大家好,我是干货哥!今天我们继续深入探讨质数判断的那些事儿。你可能以为质数判断无非就是用除法轮番上阵,其实没错,但如果我告诉你,可以通过一些运算让这些常见的方法速度翻倍,甚至百倍,你信不信?今天,我就带你揭秘如何用运算优化,让质数判断变得飞一般的快!
1. 基本方法:试除法
你可能最先想到的质数判断方法就是试除法。它的思路简单明了:要判断一个数 ( n ) 是否是质数,只要尝试用比它小的数去除它,如果找不到可以整除它的数,那 ( n ) 就是质数。乍一看,这方法没啥毛病,但效率实在不敢恭维。要是碰上个大数,你可能得挨个儿除上几十万次。
最基本的:位运算优化:
-
偶数优化:判断一个数是否是偶数,我们通常会用
n % 2 == 0
。但你可能不知道,位运算更快!只需n & 1 == 0
,轻轻一操作,速度直接上来了。 -
跳过明显非质数:你知道所有能被 2 或 3 整除的数都不是质数,那还需要傻傻地继续计算吗?不!我们用位运算快速跳过。
def is_prime_basic(n):
if n <= 1:
return False # 1 和更小的数都不是质数
if n <= 3:
return True # 2 和 3 是质数
if (n & 1) == 0 or n % 3 == 0:
return False # 偶数或能被3整除的数都不是质数
i = 5
while i * i <= n:
if n % i == 0 or n % (i + 2) == 0:
return False # 如果 n 能被 i 或 i+2 整除,则 n 不是质数
i += 6
return True
你以为这就结束了?我们来点更高级的!
2. “6k ± 1”优化
你可能以为试除法就这么简单?NO,NO,NO!试除法还可以进一步优化。除了直接跳过偶数和3的倍数外,我们可以利用一个更高级的技巧:6k ± 1。别看这个公式简单,它的实际作用却非常强大!
什么是“6k ± 1”?其实就是6的倍数减去1和加上1的位置,比如 5 和 7,11 和 13,17 和 19 等等。因为质数除了2和3,其他质数都可以写成 6k ± 1 的形式。利用这一点,我们可以把试除法的次数再减少一半!
def is_prime_6k_1(n):
if n <= 1:
return False
if n <= 3:
return True
if (n & 1) == 0 or n % 3 == 0:
return False
i = 5
while i * i <= n:
if n % i == 0 or n % (i + 2) == 0:
return False
i += 6
return True
通过这种优化,试除法的效率直接飙升!再也不用担心慢得要死的情况了。
你以为这就是巅峰了?复杂算法才刚刚登场!
上面这些优化是不是已经让你感到惊喜?不过,这只是个开胃菜!接下来,干货哥带你进入质数判断的高级阶段,让你见识一下真正的质数判断法——那些用上位运算、概率算法、甚至筛法来进行质数判断的“重武器”。
蒙特卡罗算法:质数判断中的蒙面高手!
你可能会想,判断一个数是不是质数,直接从2开始除,能整除的就不是质数,不能整除的就是质数,这不是理所当然吗?但是,真的是这样吗?很多人都这么做,但真的对吗?蒙特卡罗算法要对你说“NO”!
蒙特卡罗算法可是质数判断中的蒙面高手,它不仅速度飞快,还能让你在没搞清楚的情况下,赌一个结果——是的,你没听错,它是基于概率的!你以为概率算法就是不靠谱?那你就错了!蒙特卡罗算法就是这么狂,利用费马小定理,以一种近乎魔法的方式来验证一个数是否为质数。只要你选择的“随机种子”足够神秘,它的准确性就会让你大吃一惊!但你也要小心,虽然它大多数时候是对的,但偶尔它也会出错,这正是它神秘和有趣的地方!
import random
# 计算 base^exp % mod 的快速幂方法
def power_mod(base, exp, mod):
result = 1 # 初始化结果
base = base % mod # 处理 base 可能大于 mod 的情况
while exp > 0:
# 如果当前指数是奇数,乘上当前的 base
if exp & 1: # 等价于 exp % 2 == 1
result = (result * base) % mod
exp >>= 1 # 指数除以2(使用位运算右移一位)
base = (base * base) % mod # base 自乘,并取模
return result
# 蒙特卡罗算法判断质数
def is_prime_monte_carlo(n, k=5):
if n <= 1:
return False # 1 和更小的数都不是质数
if n <= 3:
return True # 2 和 3 是质数
if (n & 1) == 0 or n % 3 == 0:
return False # 排除 2 和 3 以外的偶数以及被3整除的数
for _ in range(k):
# 随机选择一个 a,范围是 [2, n-2]
a = random.randint(2, n - 2)
# 使用快速幂计算 a^(n-1) % n,如果结果不等于1,n一定不是质数
if power_mod(a, n - 1, n) != 1:
return False
# 经过 k 次测试后仍然没有被判定为合数,那么有较高概率是质数
return True
埃拉托色尼筛法:质数判断的终极武器!
质数判断还有一位重量级选手——埃拉托色尼筛法!你以为质数判断只是逐个排查?那你对这位选手完全低估了!埃拉托色尼筛法不是慢吞吞地排查每一个数,而是像一个战术高手,直接用大扫除的方式剔除所有的非质数,简直是质数世界的“终极武器”!
埃拉托色尼筛法的威力在于它的效率,只要你设定了一个范围,它就能飞速地筛出所有的质数。而这个过程简直就像“扫雷”一样:从2开始,把所有2的倍数都标记为非质数,然后是3,再把3的倍数都干掉,依次进行,直到你筛完所有可能的质数。最后剩下的那些,才是真正的精英!是不是很酷?
# 埃拉托色尼筛法实现的质数判断
def sieve_is_prime(n):
if n <= 1:
return False # 1 和更小的数都不是质数
# 创建一个布尔列表,初始化为 True,表示所有数字都是潜在的质数
sieve = [True] * (n + 1)
sieve[0] = sieve[1] = False # 0 和 1 不是质数
# 遍历所有小于等于 sqrt(n) 的数
for i in range(2, int(n**0.5) + 1):
if sieve[i]: # 如果 i 是质数
# 将 i 的所有倍数标记为合数
for j in range(i * i, n + 1, i):
sieve[j] = False
# 返回 n 是否是质数
return sieve[n]
这就是今天的内容,喜欢的话记得点赞、收藏和分享!我是干货哥,我们下次再见!
怎么样,干货是不是足够硬核?从基础的试除法,到“6k ± 1”优化,再到蒙特卡罗算法和埃拉托色尼筛法,质数判断的世界比你想象的还要丰富和复杂。而且,只要用上位运算,你的算法就能像火箭一样飞速提升!
还想了解更多的编程干货?别忘了关注干货哥,下次我们继续为你带来更多惊喜!