Willans 公式生成第 n 个素数的 Python 实现与溢出修复指南
发布时间 - 2025-12-27 00:00:00 点击率:次本文详解 willans 公式在 python 中的实际应用,分析 `factorial(j-1)` 导致的浮点溢出根本原因,并提供基于模 2π 化简、高精度计算和数学优化的完整解决方案,使公式可稳定计算至第 10 个素数及以上。
Willans 公式是一类纯数学构造的素数生成公式,其核心思想是利用三角函数(如余弦)的取值特性编码 Wilson 定理:当且仅当 $ j $ 是素数时,$ (j-1)! \equiv -1 \pmod{j} $,即 $ \frac{(j-1)! + 1}{j} $ 为整数,此时 $ \cos\left(\pi \cdot \frac{(j-1)! + 1}{j}\right) = \pm 1 $,其平方为 1;否则结果落在 $ (-1,1) $ 内,平方后小于 1,向下取整为 0。因此内层求和 sum 实际统计了区间 $[1,i]$ 内的素数个数 $ \pi(i) $。
但原始实现存在严重缺陷:当 j 增大(例如 $ j \geq 18 $),factorial(j-1) 迅速突破 $10^{15}$ 量级,而 math.cos() 要求输入为 float——Python float 仅能精确表示约 $2^{53} \approx 9 \times 10^{15}$ 以内的整数,超出后转 float 即丢失精度,且对极大数取模 2π 时,浮点误差被急剧放大,最终触发 OverflowError 或返回无意义值。
✅ 正确解法不是强行用 Decimal 替换 float(math.cos 不支持 Decimal),而是数学化简:利用余弦函数周期性
$$
\cos(\pi x) = \cos\big(\pi \cdot (x \bmod 2)\big)
$$
因为 $ \cos(\theta) = \cos(\theta \bmod 2\pi) $,而此处角度为 $ \pi x $,故只需将 $ x = \frac{(j-1)! + 1}{j} $ 对 2 取模,即计算 $ x \bmod 2 $。注意:$ x $ 是有理数,但 $ (j-1)! + 1 $ 除以 $ j $ 的整数部分不影响模 2 结果——关键在于判断该商是奇数还是偶数(因 $ \cos(k\pi) = (-1)^k $)。
更进一步,由 Wilson 定理:
- 若 $ j $ 是素数,则 $ (j-1)! \equiv -1 \pmod{j} \Rightarrow (j-1)! + 1 \equiv 0 \pmod{j} $,商为整数;
- 若 $ j $ 是合数且 $ j > 4 $,则 $ j \mid (j-1)! $,故 $ (j-1)! + 1 \equiv 1 \pmod{j} $,商非整数 → $ \cos^2 $ 值
- 特殊小合数 $ j=1,4 $ 需单独处理($ j=1 $ 无定义,$ j=4 $:$ 3!+1 = 7 $,$ 7/4 = 1.75 $,$ \cos^2(\pi \cdot 1.75) = \cos^2(1.75\pi) = \sin^2(0.25\pi) = 0.5 $ → floor 为 0)。
因此,无需计算超大阶乘!只需判断 $ j $ 是否为素数(用试除法),即可直接得到 floor(cos²(...)) 的值:
def is_prime(x):
if x < 2:
return False
if x == 2:
return True
if x % 2 == 0:
return False
for i in range(3, int(x
**0.5) + 1, 2):
if x % i == 0:
return False
return True
def nth_prime(n):
if not isinstance(n, int) or n < 1:
raise ValueError("n must be a positive integer")
# 估算上界:第 n 个素数 < n*(log n + log log n) (n≥6),保守取 2**n 不必要且低效
# 改用动态扩展搜索范围
candidate = 2
count = 0
while count < n:
if is_prime(candidate):
count += 1
if count == n:
return candidate
candidate += 1
return candidate⚠️ 注意事项:
- Willans 公式本质是“存在性证明”,非实用算法:时间复杂度为 $ O(2^n \cdot n!) $,比朴素试除慢数个数量级;
- 原始代码中 2**n 上界过于宽松(第 8 个素数是 19,却遍历到 256),应改用素数定理估算或动态增长;
- pow(n / sum, 1/n) 在 sum=0 时会报错(如 i=1 时无素数),需加保护;
- math.floor(pow(...)) 可简化为 int(...),但逻辑不变。
? 总结:面对数学公式的编程实现,优先考虑符号化约简而非数值硬算。Willans 公式的价值在于理论趣味性,工程中请始终选用筛法(如埃氏筛、分段筛)或优化试除。若坚持公式验证,建议用 SymPy 进行符号计算,避免浮点陷阱。
# python
# 编码
# app
# ai
# cos
# overflow
# 三角函数
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
百度浏览器ai对话怎么关 百度浏览器ai聊天窗口隐藏
青岛网站建设如何选择本地服务器?
Laravel如何使用Collections进行数据处理?(实用方法示例)
国美网站制作流程,国美电器蒸汽鍋怎么用官方网站?
Laravel Vite是做什么的_Laravel前端资源打包工具Vite配置与使用
EditPlus中的正则表达式 实战(1)
如何快速查询域名建站关键信息?
如何用美橙互联一键搭建多站合一网站?
公司门户网站制作流程,华为官网怎么做?
大学网站设计制作软件有哪些,如何将网站制作成自己app?
电商网站制作价格怎么算,网上拍卖流程以及规则?
Laravel怎么连接多个数据库_Laravel多数据库连接配置
Laravel如何使用Scope本地作用域_Laravel模型常用查询逻辑封装技巧【手册】
长沙企业网站制作哪家好,长沙水业集团官方网站?
Laravel如何处理文件下载请求?(Response示例)
详解Android中Activity的四大启动模式实验简述
Laravel观察者模式如何使用_Laravel Model Observer配置
再谈Python中的字符串与字符编码(推荐)
JavaScript如何实现继承_有哪些常用方法
大连 网站制作,大连天途有线官网?
魔毅自助建站系统:模板定制与SEO优化一键生成指南
惠州网站建设制作推广,惠州市华视达文化传媒有限公司怎么样?
Laravel如何获取当前用户信息_Laravel Auth门面获取用户ID
潮流网站制作头像软件下载,适合母子的网名有哪些?
Laravel如何优化应用性能?(缓存和优化命令)
Laravel如何生成PDF或Excel文件_Laravel文档导出工具与使用教程
如何确认建站备案号应放置的具体位置?
车管所网站制作流程,交警当场开简易程序处罚决定书,在交警网站查询不到怎么办?
JavaScript如何实现路由_前端路由原理是什么
Laravel如何自定义错误页面(404, 500)?(代码示例)
制作ppt免费网站有哪些,有哪些比较好的ppt模板下载网站?
创业网站制作流程,创业网站可靠吗?
如何在云虚拟主机上快速搭建个人网站?
详解阿里云nginx服务器多站点的配置
Laravel怎么实现软删除SoftDeletes_Laravel模型回收站功能与数据恢复【步骤】
Laravel的辅助函数有哪些_Laravel常用Helpers函数提高开发效率
中国移动官方网站首页入口 中国移动官网网页登录
如何在云主机上快速搭建多站点网站?
如何在不使用负向后查找的情况下匹配特定条件前的换行符
如何在Windows 2008云服务器安全搭建网站?
laravel怎么为API路由添加签名中间件保护_laravel API路由签名中间件保护方法
Laravel Seeder怎么填充数据_Laravel数据库填充器的使用方法与技巧
教你用AI将一段旋律扩展成一首完整的曲子
如何在腾讯云免费申请建站?
Laravel如何优雅地处理服务层_在Laravel中使用Service层和Repository层
油猴 教程,油猴搜脚本为什么会网页无法显示?
JS去除重复并统计数量的实现方法
郑州企业网站制作公司,郑州招聘网站有哪些?
网站页面设计需要考虑到这些问题
Android自定义控件实现温度旋转按钮效果


**0.5) + 1, 2):
if x % i == 0:
return False
return True
def nth_prime(n):
if not isinstance(n, int) or n < 1:
raise ValueError("n must be a positive integer")
# 估算上界:第 n 个素数 < n*(log n + log log n) (n≥6),保守取 2**n 不必要且低效
# 改用动态扩展搜索范围
candidate = 2
count = 0
while count < n:
if is_prime(candidate):
count += 1
if count == n:
return candidate
candidate += 1
return candidate