尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

尺规作图极限:用Manim动画演示正65537边形的数学原理与实现

尺规作图极限:用Manim动画演示正65537边形的数学原理与实现 如果你的首页刷到过《【全网首个】尺规作图正65537边形完整过程manim动画尺规作图的癫疯》这种标题大概会有两种反应一种是觉得“标题党又来骗点击了”另一种是好奇“正65537边形到底有没有可能用尺规画出来”。答案是理论上可以工程上极其离谱视觉上约等于一个圆。这篇文章我就从数学原理、尺规作图的判定依据、到一个完整可运行的 Manim 动画工程把正 65537 边形这件事彻底拆开讲清楚。即使你完全没接触过 Manim只要会一点 Python也能在本地跑出属于你自己的“尺规作图极限挑战”动画。本文会覆盖费马素数和高斯判据、为什么正 65537 边形可以通过尺规作图构造、Manim 环境搭建、从正 3 边形到正 65537 边形的动画对比、顶点坐标级的高阶多边形绘制以及渲染大数据量几何对象时的性能优化建议。1. 一个“画不出来”的多边形为什么值得研究1.1 正65537边形的特殊性先区分两个概念。我们现在讨论的“尺规作图”默认只允许两种工具没有刻度的直尺和圆规。用这两种工具能不能作出一个正 n 边形不是你想当然画一个“近似圆”就可以了而是要求所有的顶点在逻辑上都必须是精确可构造的。正三角形、正方形、正五边形很早就被人画出来了。正七边形反而是古希腊几何学家一直卡住的问题。为什么数字一变大难度反而不按常理变化因为一个正 n 边形能不能用尺规作图取决于 n 的数学结构而不是取决于边数多少。正 65537 边形之所以特殊是因为 65537 本身是 2 的 16 次方加 1也就是65537 2^16 1同时 65537 是一个素数。像这种形如 2^(2^k) 1 的数叫做费马数。目前人类确认的费马素数只有前 5 个分别是 3、5、17、257 和 65537。第 6 个费马数 2^32 1 已经是合数后面目前也没有发现新的费马素数。这个“恰好是费马素数”的属性让正 65537 边形成为数学上允许尺规作图的边数之一。1.2 高斯定理与可作图判据高斯在 19 岁左右证明了这样一个非常漂亮的结论一个正 n 边形可以尺规作图当且仅当 n 可以写成n 2^k × p1 × p2 × … × pr其中 p1、p2、…、pr 是互不相同的费马素数k 是非负整数。这个结论为什么成立简单理解尺规作图能处理的本质操作是“解二次方程”。一个复数单位根能不能用尺规构造取决于它所在的数域中的扩张次数是否是 2 的幂。对于正 n 边形需要构造 n 次单位根而 n 次单位根所在的数域扩张次数等于欧拉函数 φ(n)。只有当 φ(n) 是 2 的幂时才能通过有限次开平方操作构造出来。对于 n 65537φ(65537) 65536 2^16正好是 2 的幂。因此正 65537 边形在原理上完全可以用尺规作图构造出来。1.3 为什么说它是尺规作图的“癫疯”既然数学上可行那实际操作呢这里才是“癫疯”的地方。高斯虽然给出了正 17 边形的尺规作图方法但对于正 65537 边形真正给出完整作图方案的人是德国数学家赫尔梅斯Johann Gustav Hermes。他花了大概 10 年时间整理出一套理论上可行的作图步骤最终的手稿超过 200 页至今还保存在哥廷根大学图书馆。注意这只是“作图方案”不是真的在纸上画出来一个肉眼可辨认的 65537 边形。因为按照这套方案执行步骤数量会是天文数字实际物理作图根本不可能完成。更直观地说如果一个正 65537 边形的外接圆半径是 1 米那么它的每条边大约只有 0.096 毫米肉眼很难分辨每个顶点在哪里。整个图形看起来就是一个完美圆形。所以这个项目标题说的“完整过程”准确理解应该是“完整描述构造原理和视觉呈现”而不是真的播放出几百万步圆规直尺操作。2. 数学准备从费马素数到高斯判据2.1 费马数序列费马数的一般形式是F_k 2^(2^k) 1前几项为F0 3F1 5F2 17F3 257F4 65537其中前 5 项都是素数。F5 4294967297 641 × 6700417不是素数。所以目前已知的费马素数只有 5 个。这些数之所以在尺规作图问题里有特殊地位是因为高斯判据中“互不相同的费马素数”这一条件。正 15 边形可以作图因为 15 3 × 5正 51 边形可以作图因为 51 3 × 17正 65537 边形可以作图因为 65537 本身就是一个费马素数。2.2 高斯判据的使用方法实际判断一个正 n 边形是否可以尺规作图不需要真的去数因数。可以直接计算欧拉函数 φ(n)然后检查 φ(n) 是否是 2 的幂。例如n 7φ(7) 6不是 2 的幂所以正七边形不能尺规作图。n 17φ(17) 16 2^4可以。n 257φ(257) 256 2^8可以。n 65537φ(65537) 65536 2^16可以。当然这个判据是“存在构造方案”不是真的推荐你去画。在动画中我们真正能做的是把这些多边形尽可能多地绘制出来去感受不同边数带来的视觉变化。2.3 单位根视角的补充理解从复数角度看正 n 边形就是把单位圆上的 n 等分点依次连接起来。这些等分点对应的复数是方程x^n − 1 0的根也就是e^(2πik/n)其中 k 0, 1, 2, …, n − 1当 n 是费马素数时n 次单位根所在的分圆域恰好是 2 的幂次扩张。因此只需要逐层解二次方程就能把这些根表示成有限次加减乘除和开平方的表达式。这也是高斯判据的底层逻辑。以后你在别的资料里看到“正 257 边形由某位数学家作出”提到“分圆多项式”“二次扩张”本质都是这一套思路。2.4 实际作图的规模以正 65537 边形为例如果外接圆半径为 r中心角是θ 2π / 65537 ≈ 0.0000959 弧度转化为度数约 0.00549 度。如果半径是 1 单位边长大约是2 × sin(θ/2) ≈ 0.0000959假设你在一个半径 400 像素的圆上画 65537 个顶点每个相邻顶点的像素距离大约为400 × 0.0000959 ≈ 0.0384 像素也就是说在标准分辨率下顶点间距小于一个像素。这就是为什么任何渲染工具画出来的正 65537 边形视觉上都只能是一个圆。3. Manim 环境准备与项目组织如果你已经熟悉 Manim可以直接跳到第 4 节。如果不熟悉下面这套环境搭建步骤足够帮你把动画跑起来。3.1 安装 Manim本文使用的是 Manim 社区版也就是 GitHub 上 3b1b 官方项目衍生出来的社区维护版本。安装命令pip install manim如果你使用虚拟环境python -m venv venv source venv/bin/activate # Windows 下是 venv\Scripts\activate pip install manim安装完成后可以查看版本信息manim --version3.2 依赖项说明Manim 渲染需要以下几个外部程序依赖作用说明Python 3.8运行环境Manim 依赖 Python 3.8 及以上版本FFmpeg视频编码不安装会无法导出 mp4LaTeX可选渲染数学公式不带 LaTeX 也能用部分文本但 MathTex 依赖它Cairo / Pango字体和图形渲染pip 安装 manim 时会自动处理FFmpeg 的安装方式根据操作系统有所不同。macOS 可以用brew install ffmpegUbuntu 可以用sudo apt install ffmpegWindows 用户建议从 FFmpeg 官网下载编译好的二进制文件并把 bin 目录添加到系统 PATH。如果暂时不想装 LaTeX可以先用Text()和MathTex()之外的基础图形。但要显示数学公式还是建议安装 TeX 发行版。macOS 推荐 MacTeXUbuntu 推荐 texlive-latex-extraWindows 推荐 TeX Live。3.3 项目文件结构本文示例项目结构如下fermat-polygon/ ├── scenes/ │ ├── __init__.py │ ├── basic_polygons.py │ ├── hex65537.py │ └── compass_demo.py ├── media/ │ ├── videos/ │ └── images/ ├── requirements.txt └── README.md实际演示时为了简单可以直接把多个 Scene 类写在一个.py文件里用 Manim 命令行参数选择要渲染的类。下面统一使用这种单文件组织方式。4. 用 Manim 绘制正多边形4.1 最简单的正多边形动画先写一个最小可运行示例# 文件路径basic_polygons.py from manim import * class PentagonDemo(Scene): def construct(self): polygon RegularPolygon(5, radius2, colorBLUE) self.play(Create(polygon)) self.wait()这段代码创建了一个正五边形并使用Create动画把它绘制出来。RegularPolygon是 Manim 内置的多边形类第一个参数是边数第二个参数是外接圆半径。运行命令manim -pql basic_polygons.py PentagonDemo其中-p表示渲染完成后预览-ql表示低画质。低画质渲染速度更快开发调试时够用。如果要输出高清manim -qh basic_polygons.py PentagonDemo4.2 对比正3、正5、正17、正257的多边形为了直观感受不同边数的差异我们可以把正三角形、正五边形、正十七边形、正二百五十七边形放到同一个场景里对比from manim import * class PolygonComparison(Scene): def construct(self): captions [(正三角形, 3), (正五边形, 5), (正十七边形, 17), (正二百五十七边形, 257)] for i, (text, n) in enumerate(captions): polygon RegularPolygon(n, radius2) label Text(text, font_size36).next_to(polygon, DOWN) self.play(Create(polygon), FadeIn(label)) self.wait(1) if i len(captions) - 1: self.play(FadeOut(polygon), FadeOut(label))运行manim -pql basic_polygons.py PolygonComparison注意当 n 等于 257 时RegularPolygon生成的图形在视觉上已经非常接近圆。这是正常的因为在 400 像素级别的分辨率里257 条边的折线和圆的差距已经很小。从这里就能推想真正的 65537 边形在高清视频里看起来必然是一个圆。4.3 运行结果说明渲染完成后默认输出目录是media/videos/basic_polygons/。文件名类似PolygonComparison-480p15.mp4480p15表示低画质 480p、15 帧每秒。如果使用-qh会生成比较清晰的 1080p 视频。5. 进阶实战绘制正65537边形5.1 用顶点坐标构造 Polygon由于RegularPolygon在边数非常大时可能不是最优路线我们可以直接用数学方式计算所有顶点坐标再用Polygon创建对象。# 文件路径hex65537.py from manim import * import numpy as np class Hex65537Visual(Scene): def construct(self): n 65537 radius 3.0 vertices [ np.array([ radius * np.cos(TAU * i / n), radius * np.sin(TAU * i / n), 0 ]) for i in range(n) ] polygon Polygon(*vertices, colorBLUE) # 直接 add避免 Create 在 65537 条边上做逐段动画 self.add(polygon) self.wait()这段代码的核心是TAU是 Manim 内置常量等于 2π。对 i 0 到 65536依次计算顶点在单位圆上的坐标。将这 65537 个顶点传入Polygon。使用self.add()直接显示而不是self.play(Create(polygon))。运行manim -pql hex65537.py Hex65537Visual5.2 为什么建议用 add 而不是 CreateCreate的作用是让一个 VMobject 从“没有”到“完整”动态显示。对于 3 条边、5 条边的多边形这个动态效果非常漂亮。但是对于 65537 条边Create会在每一帧里不断更新大量的路径导致计算量爆炸甚至可能出现渲染一个几十秒动画需要几个小时的情况。如果只是想展示正 65537 边形的视觉形态直接self.add(polygon)然后self.wait()就足够了。这样视频里一开始就是完整的“圆”不会因为逐帧绘制而卡死。5.3 让画面更直观增加文字说明为了让观众明白“这是一个正 65537 边形”可以在画面中同时显示相关公式class Hex65537WithText(Scene): def construct(self): n 65537 radius 2.8 vertices [ np.array([ radius * np.cos(TAU * i / n), radius * np.sin(TAU * i / n), 0 ]) for i in range(n) ] polygon Polygon(*vertices, colorBLUE) formula MathTex(r65537 2^{16} 1) label Text(正65537边形, font_size36) formula.move_to(UP * 2.5) label.next_to(formula, DOWN) self.add(polygon, formula, label) self.wait()MathTex使用 LaTeX 语法渲染公式。2^{16}表示 2 的 16 次方。如果你的系统没有安装 LaTeX这一行会报错可以改成Text(65537 2^16 1)。运行manim -pql hex65537.py Hex65537WithText渲染出来的视频画面看起来就是一个蓝色圆形但左下角或顶部有清晰的公式和名称说明。这个“视觉上是圆数学上是 65537 个顶点”的反差就是整个动画最有冲击力的一点。6. 尺规作图过程的动画拆解6.1 尺规作图基本动作真正意义上的尺规作图动画应该包含两种基本动作画圆和画直线。在 Manim 中这分别对应Circle和Line。先看一个最简单的效果from manim import * class BasicCompassAction(Scene): def construct(self): # 定义两个圆心点 A np.array([-2, 0, 0]) B np.array([2, 0, 0]) # 画线段 AB segment Line(A, B, colorWHITE) # 分别以 A、B 为圆心半径 4 画圆 circle_A Circle(radius4, colorYELLOW).move_to(A) circle_B Circle(radius4, colorBLUE).move_to(B) self.play(Create(segment)) self.play(Create(circle_A), Create(circle_B)) self.wait()运行manim -pql compass_demo.py BasicCompassAction这里展示了尺规作图里最常见的操作已知一条线段在线段两端分别作等半径圆两个圆的交点就是构造新几何对象的关键点。6.2 演示“过中点作垂线”两个等圆的交点连线就是线段 AB 的垂直平分线。这个操作可以如下实现class PerpendicularBisector(Scene): def construct(self): A np.array([-2, 0, 0]) B np.array([2, 0, 0]) h np.sqrt(12) # sqrt(4^2 - 2^2) segment Line(A, B, colorWHITE) circle_A Circle(radius4, colorYELLOW).move_to(A) circle_B Circle(radius4, colorBLUE).move_to(B) P1 np.array([0, h, 0]) P2 np.array([0, -h, 0]) dot_P1 Dot(P1, colorRED) dot_P2 Dot(P2, colorRED) bisector Line(P1, P2, colorGREEN) self.play(Create(segment)) self.play(Create(circle_A), Create(circle_B)) self.play(FadeIn(dot_P1), FadeIn(dot_P2)) self.play(Create(bisector)) self.wait()这里的h sqrt(12)来自于勾股定理圆半径是 4圆心到中点的距离是 2所以交点到中点的距离是 √(4² − 2²) √12。正 17 边形的尺规作图本质上就是不断重复这种“构造圆交点、连线、取中点、作垂线、开平方”的操作。只不过嵌套层级更多需要对复数域上的二次方程反复求解。6.3 从基本操作到正17边形的构造思路正 17 边形之所以能尺规作图是因为 17 次单位根可以通过嵌套平方根形式表达cos(2π/17) 的表达式大约包含多层根号具体形式如下cos(2π/17) −1/16 (√17)/16 ...这串长表达式看起来很复杂但它只包含整数、加减乘除和平方根正好就是尺规作图能处理的数。因此理论上我们可以用 Manim 做出一整套“逐步构造正 17 边形”的动画每一层动画就是一次画圆和连线。6.4 为什么正65537边形的动画不能逐帧播放很多人会问“既然正 17 边形可以逐帧演示构造过程那正 65537 边形为什么不能”答案很简单步骤数量级不一样。正 17 边形的构造依赖于 4 层二次方程扩张φ(17) 16 2^4正 65537 边形的构造依赖于 16 层二次方程扩张φ(65537) 65536 2^16虽然 16 看起来不大但每一层都需要在前一层的基础上递归构造大量中间点。赫尔梅斯当年整理出的完整作图方案超过 200 页手稿。就算我们把每个基本操作缩成 1 秒的动画实际播放时间也远超正常视频长度更不用说渲染时间和内存消耗。所以工程上合理的选择是用 Manim 演示“大边形视觉极限”再用少量基本动作动画解释“尺规作图逻辑”而不是强行模拟全程。7. 常见渲染问题与排查7.1 常见问题表格问题现象常见原因解决思路manim 命令找不到Python Scripts 目录未加入 PATH重新安装或把python -m manim作为替代渲染视频只有几秒黑屏场景里没有对象或没有self.wait()在场景末尾增加self.wait()MathTex 报错系统未安装 LaTeX安装 TeX 发行版或改用Text中文文字乱码缺少中文字体安装字体并给Text指定font参数65537 边形渲染非常慢顶点数量太大且使用Create改用self.add()直接显示输出视频卡顿帧率或分辨率过高开发阶段用-ql降低画质Video 目录为空渲染未完成或代码报错查看终端日志确认 Scene 类名7.2 渲染慢的具体排查顺序如果你渲染hex65537.py时感觉卡顿可以按以下顺序排查确认是否使用了Create。如果是改成self.add()。确认是否设置了过高的pixel_width和pixel_height。开发阶段建议 854×480。确认run_time是否设置过大。大数据量图形直接add后wait即可。检查内存占用。如果机器内存小于 8GB建议关掉其他程序再渲染。7.3 中文乱码问题处理如果Text(正65537边形)显示为方框说明字体缺失。可以手动指定字体Text(正65537边形, fontNoto Sans CJK SC, font_size36)不同系统的字体名不同。Windows 可以尝试Microsoft YaHeimacOS 可以尝试PingFang SCLinux 可以尝试Noto Sans CJK SC。8. 最佳实践与工程建议8.1 把动画场景拆成多个小场景不要把整个动画写成一个大场景。比如把“展示公式”“绘制正五边形”“对比正十七边形”“渲染正65537边形”分别写成独立的Scene类再通过 Manim 命令行逐个渲染。这样能避免单场景内存过高也方便调试。8.2 大数据量几何对象处理处理上万级顶点时建议优先使用数组计算而不是循环。例如t np.arange(n) * TAU / n points np.zeros((n, 3)) points[:, 0] radius * np.cos(t) points[:, 1] radius * np.sin(t)Numpy 批量计算比逐项追加快得多。如果顶点数量达到百万级甚至可以考虑先用较低分辨率画布渲染再后期放大。8.3 数学内容严谨性在做数学类动画时务必检查三点公式是否准确。比如65537 2^16 1不能写成2^16 - 1。术语是否规范。比如“费马素数”和“费马数”是不同概念。视频中的每一步构造是否符合几何规则。如果只是演示视觉极限文字说明里应该写“数学上可尺规作图”而不是“上面就是正65537边形的尺规作图全部步骤”。8.4 输出视频格式与发布建议Manim 默认输出 MP4。如果你的目标是发到 CSDN 或者 B 站建议使用-qh渲染最终版同时保留一个-ql的开发版本。视频分辨率建议 1920×1080帧率保持默认 15 或 30 均可。发布到博客时除了嵌入视频还可以把运行命令和关键代码段落一起放上去方便读者复现。这样文章的收藏价值会明显提高。9. 总结正 65537 边形从数学上看是高斯判据下的一个极端案例边数是费马素数欧拉函数值是 2 的幂所以在尺规作图的框架里确实可以构造。但从物理世界来看它几乎不可能被真正画成一张肉眼可辨认的图哪怕你有一台运算能力极强的电脑最终渲染结果也只是一个圆形。通过 Manim我们可以用很短的代码把这个“理论可行实际近似圆形”的数学对象可视化出来。更进一步我们还能用Circle、Line、Dot这些基础几何对象模拟尺规作图的核心操作让观众理解复杂的多边形构造思路。如果你想继续深入可以尝试用 Manim 完整演示正 17 边形的尺规作图过程用动画展示分圆多项式和复数单位根的关系对比正 3、5、17、257、65537 边形在相同外接圆下的边长收缩趋势尝试手动实现一个简单的“尺规作图模拟器”把圆与直线的交点计算逻辑封装起来。如果本文对你有帮助欢迎收藏备用。也欢迎在评论区聊聊你自己在用 Manim 做过哪些数学可视化尝试尤其是那些和数据量、性能有关的“极限场景”。
返回列表