惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

G
GRAHAM CLULEY
V
V2EX
WordPress大学
WordPress大学
博客园 - Franky
Last Week in AI
Last Week in AI
博客园 - 司徒正美
有赞技术团队
有赞技术团队
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
博客园 - 【当耐特】
V
Visual Studio Blog
C
CERT Recently Published Vulnerability Notes
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Jina AI
Jina AI
Attack and Defense Labs
Attack and Defense Labs
腾讯CDC
The Hacker News
The Hacker News
Hugging Face - Blog
Hugging Face - Blog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
J
Java Code Geeks
人人都是产品经理
人人都是产品经理
阮一峰的网络日志
阮一峰的网络日志
T
Tailwind CSS Blog
S
SegmentFault 最新的问题
大猫的无限游戏
大猫的无限游戏
小众软件
小众软件
A
Arctic Wolf
量子位
博客园 - 聂微东
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
N
News and Events Feed by Topic
雷峰网
雷峰网
博客园_首页
Google Online Security Blog
Google Online Security Blog
Spread Privacy
Spread Privacy
罗磊的独立博客
H
Hacker News: Front Page
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
月光博客
月光博客
TaoSecurity Blog
TaoSecurity Blog
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
博客园 - 三生石上(FineUI控件)
宝玉的分享
宝玉的分享
IT之家
IT之家
The Cloudflare Blog
爱范儿
爱范儿
博客园 - 叶小钗
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Apple Machine Learning Research
Apple Machine Learning Research
酷 壳 – CoolShell
酷 壳 – CoolShell

博客园_首页

Linux实操--组管理、权限管理和定时任务 Java + EasyExcel 实现单个接口导出多个Excel Mem0 源码解析系列(二):提示词工程的深度剖析 Openclaw TaskFlow究竟是什么?和普通Skill技能有什么区别 博文阅读密码验证 - 博客园 嘉立创开源:应该是全网MicroPython教程最多的开发板 Hermes Agent 集成实践:从协议到生产 2026年AI编程工具横评:Cursor、Codex、Claude Code、Zed、Windsurf Java程序员必看的RAG入门教程 2026 AI效率神器:Superpowers + Claude Code 保姆级教程 本地大模型部署全攻略:从 0 到 1 玩转 Ollama 【从0到1构建一个ClaudeAgent】内存管理-上下文压缩 .NET 高级开发 | 设计、实现一个事件总线框架 电子小白入门之NE555 3. WorkBuddy:隐藏玩法,一键召唤专家,让 AI 以"专家身份"给你干活 和AI一起搞事情#3:Claude Teammate 游戏开发翻车实录 【OpenClaw】通过 Nanobot 源码学习架构---(7)Memory C# .NET 周刊|2026年3月3期 我在 Debian 11 上把 K8s 单机搭起来了,过程没你想的那么顺(/opt 目录版) 深度学习进阶(七)Data-efficient Image Transformer CLI+Skill搭建浏览器AI自动化框架,告别一切重复枯燥任务 告别Token账单无底洞:OpenClaw本地部署,重塑企业数据主权的唯一解 FastAPI+Vue:文件分片上传+秒传+断点续传,这坑我帮你踩平了! SBTI 爆火后,我做了个程序员版的 CBTI。。已开源 + 附开发过程 多模态检索开始进入工程期:用 Sentence Transformers 搭建可落地的 Multimodal RAG 100多行代码实现一个最简单的Agent(用ReAct) Claude Code 通关手册(八):推荐 5 个 Hooks,代码质量提升 3 倍 老板:“有人截图了!”。安全部门:“收到,马上查暗水印!” - why技术 技术之外,皆是人间 C#/.NET/.NET Core技术前沿周刊 | 第 69 期(2026年4.01-4.12) Snack JSONPath 项目架构分析 Claude Code Buddy 小析:一个非核心功能,如何体现产品的细节完成度 AI新时代下的图床管理方案-Cloudflare图床+MCP+Skills方案指南 化繁为简:顺丰速运App如何通过 HarmonyOS SDK实现专业级空间测量 从零实现富文本编辑器#13-React非编辑节点的内容渲染 AI开发-python-langchain框架(3-23-OpenAI Functions风格Tool Calling智能助手) .NET + AI 进阶实战:基于类的技能开发 - 打造可治理的 Agent 能力模块 【从0到1构建一个ClaudeAgent】规划与协调-技能 上周热点回顾(4.6-4.12) 电子小白的工具三件套:面包板、杜邦线、万能板 单表五亿数据的查询优化 | Mysql、StarRocks 2. WorkBuddy:从“我是谁”到“帮我干活” C# 如何减少代码运行时间:7 个实战技巧 基于HelixToolkit.SharpDX 渲染3D模型 - 笺上知微 从零开始的双臂具身VLA起源及现阶段发展综述 - SkyXZ 记对 xonsh shell 的使用, 脚本编写, 迁移及调优 - pluvium27 受够了Vibe Coding的失控?换个起点,让AI事半功倍 从开始配置漏洞环境到漏洞复现流程 - 難しい 关于10年工作经验的程序员对OpenClaw的实战经验分享以及看法 - 虚无境 Any metadata 的内存布局 C# .NET 周刊|2026年3月2期 - InCerry 我帮你测过了,测试圈排名第二的 Skill 依然很牛逼 Skill Discovery | 无监督技能发现的经典工作总结 - MoonOut PbootCMS 网站内容数量多导致访问慢?这些实用优化方案帮你提速! - 家兴网络技术工作室 上下文工程是什么?过时了么?一文讲明白! - 一枫说码 网站漏洞怎么发现并修复?一篇实用指南(附完整流程) - 家兴网络技术工作室 开了 TUN 模式还是直连?90% 的人都踩过这个坑 Github日报|2026年04月12日 - AI一族 AScript扩展多种脚本语言 - rockey627 AI 学习笔记:Agent 的记忆机制 你能被装进一个文件里吗?——7 万人把同事"蒸馏"成了 AI - 我没有三颗心脏 Claude Code 通关手册(七):给 AI 装上技能包——Skills 完全指南 - 暮色之狐 在浏览器中快速编辑代码:VSCode Web 集成实践 - Newbe36524 蒸馏自己 skill?基于 Deepseek 的蒸馏器,丐版蒸馏方式,简单便捷 - To_Carpe_Diem Spring AI Aliababa和AgentScope,哪个更好? - 苏三说技术 Etsy 把 1000 个 MySQL 分片迁进 Vitess:425TB 数据背后的真正问题不是性能,而是运维规模 MicroPython LVGL基础知识和概念:底层渲染与性能优化 - FreakStudio 数据库草图算法 Python 潮流周刊#146:CPython 引入 Rust 的进展 - 豌豆花下猫 最小生成树 - mofei1116 红日靶场七:从外网入口、容器逃逸到 AD 接管的完整利用链复盘 - YouDiscovered1t 分享四款开源且实用的 Kafka 管理工具 - 追逐时光者 vLLM 权重加载机制全解析:从挑战到理想架构 LCT 学习笔记 - ACehomoxue Avalonia UI 12.0.0 正式发布:架构演进和性能飞跃 - 张善友 当 AI Agent 把调用链拉长,延迟开始成为一门生意 conhost.exe 无法显示 U+2717 - 145a 太秀了,我把自己蒸馏成了 Skill!已开源 - 程序员鱼皮 ASP.NET Core 内存缓存实战:一篇搞懂该怎么配、怎么避坑 基于 Ghostty 带有分割标签页和为 Claude 编程设计的通知终端 - BugShare AI 焊死入口:教育的“操作系统级”重塑 - 郝hai 初级Java开发工程师使用sql脚本编写代码的过程是简单而且不糊涂 - CoderOilStation Claude Code通关手册(六):MCP协议完全指南 - 暮色之狐 边框灯光环绕动画特效实现指南 - Newbe36524 开源:子木蒸馏版的 SEO 审计工具 seo-audit-skill v1.0 我所理解的Python元模型 【从0到1构建一个ClaudeAgent】规划与协调-TodoWrite - 程序员Seven Claude 和 Codex 在审计 Skill 上性能差异探究 - ACai_sec AScript如何实现中文脚本引擎 - rockey627 【渗透测试】HTB Season10 Garfield 全过程wp - dynasty_chenzi Android 开发者为什么必须掌握 AI 能力?端侧视角下的技术变革 树状数组正确性证明 - AC-wyr 你的 AI 焦虑,可能比 AI 本身更危险——ATM 机没有消灭银行柜员,但恐慌消灭了你的判断力 - 我没有三颗心脏 一个拉胯的分库分表方案有多绝望?整个部门都在救火! - 冰河团队 动态规划入门必学之走方格问题 - Ofnoname PostgREST 与 PostgreSQL 角色权限配置全解析(生产级实践) - SheepDog1998 使用 UEFI 图形输出协议 GOP 在屏幕上显示图像的方法 - 阿源- Claude Code通关手册(五):组建你的AI专家团队,子代理系统 - 暮色之狐 一个程序员到架构师的催婚路之感悟(整整10年后的催婚相亲感悟) - MisterLip 用 Agent Skill 自动生成工作周报 - 赵康
大整数相乘的 Toom-Cook 算法
Ofnoname · 2026-05-09 · via 博客园_首页

编程时写整数乘法,通常我们不会太关心底层细节。a * b 写起来非常自然,好像一条语句就能瞬间完成。

对固定宽度整数来说,比如 32 位或 64 位整数,乘法通常确实可以由少量机器指令完成,成本可以近似看成常数。但如果是两个几千位、几万位甚至更大的整数相乘,情况就不一样了。此时 * 背后不再是一条简单的 CPU 乘法指令,而是一整套大整数乘法算法。

这篇文章要讲的,就是大整数乘法中的一个经典算法:Toom-Cook 算法

从普通乘法说起

当数值远超一个机器字或寄存器能表示的范围时,就不能再把一次整数乘法视作 \(O(1)\) 操作了。

为了简化讨论,下面把 \(n\) 理解成大整数被拆成的“单元数量”。每个单元可以是一个机器字,也可以是一段固定长度的二进制位,可以快速相乘。

小时候学过的竖式乘法,本质上就是普通乘法。如果两个整数各有 \(n\) 个单元,那么普通乘法大概要做 \(n^2\) 级别的单元乘法。

对于特别大的整数,\(n^2\) 会很快变得昂贵。

Karatsuba 算法是第一个非常经典的优化。它把一个大整数拆成两半,本来需要 4 次子乘法,但通过代数变形,只需要 3 次子乘法。它的复杂度大约是:

\[O(n^{\log_2 3}) \approx O(n^{1.585}) \]

这已经比普通乘法好不少。

而 Toom-Cook 可以看成是 Karatsuba 的推广:Karatsuba 是拆成 2 块,Toom-Cook 可以拆成 3 块、4 块、5 块甚至更多块。

不同种类的乘法

讨论大数乘法问题时,很多不同类型的“乘法”成本并不一样。这个首先要明确。

  1. 机器字乘法:如果两个数都能放进一个机器字,比如 32 位或 64 位整数,那么一次乘法通常可以看成 \(O(1)\)。这是我们平时写固定宽度整数乘法时最接近的情况。

  2. 大整数乘法:如果两个数都有很多个单元,那么 A * B 就不是一次 \(O(1)\) 操作,而是一个规模随整数长度增长的计算问题。普通竖式乘法、Karatsuba、Toom-Cook 优化的都是这一层的乘法。

  3. 大整乘小常数:比如 \( 2a_1 \),这里的 2 和 4 是固定小常数。它们通常可以通过移位和加法完成。从单个机器字的角度看,每一步很便宜;但如果整个大整数有 \(n\) 个单元,扫完整个数组仍然需要 \(O(n)\) 时间。

  4. 乘以 \(\beta\)\(\beta^i\):后面我们会把大整数写成:

\[A = a_0 + a_1\beta + a_2\beta^2 \]

这里的 \(\beta\) 是分块基数。乘以 \(\beta\)\(\beta^2\) 只需要移位、搬移和进位处理,而不是普通意义上的大整数乘法。

所以,当我们说 Toom-Cook 把 9 次乘法减少到 5 次乘法时,减少的是第 2 类:真正昂贵的大整数子乘法。

大整数如何拆成多项式

image

假设我们要计算两个大整数 \(A\)\(B\) 的乘积。要先把它们拆成若干块。

比如把 \(A\) 拆成 3 块:

\[A = a_0 + a_1\beta + a_2\beta^2 \]

这里的 \(\beta\) 可以理解成一个很大的进制基数。例如一个大整数内部用数组存储,每个数组元素存一段二进制位,那么 \(\beta\) 就对应一块的进位单位。

A = [a2][a1][a0]

假如 \(\beta = 10\),这就等价于个十百千万了(而实际上基数也可以取大得多的数)。同理 \( B = b_0 + b_1\beta + b_2\beta^2 \)

接下来,不再把 \(A\)\(B\) 仅仅看成整数,而是看成两个多项式在 \(x = \beta\) 时的取值。

也就是:

\[A(x) = a_0 + a_1x + a_2x^2 \]

\[B(x) = b_0 + b_1x + b_2x^2 \]

原来的整数 \(A\)\(B\),就是 \(A(\beta)\)\(B(\beta)\),也就是函数 \(C(x)=A(x)B(x)\),在 \(x = \beta\) 的值

Toom-Cook 的核心三步

Toom-Cook 的流程可以概括成三步:

取值 evaluation
逐点相乘 pointwise multiplication
插值 interpolation

下面以 Toom-3 为例说明。就是把整数拆成 3 块。

此时 \(A(x)\)\(B(x)\) 都是二次多项式。两个二次多项式相乘,结果是一个四次多项式:

\[C(x) = A(x)B(x) \]

四次多项式有 5 个系数:

\[C(x) = c_0 + c_1x + c_2x^2 + c_3x^3 + c_4x^4 \]

所以,只要知道它在 5 个不同点上的值,就能恢复出整个多项式。

第一步:取值

Toom-3 常用的取值点是:

0, 1, -1, 2, infinity

这里的 infinity 不是真的无穷大,也不是要带入极限。它只是一个记号,表示取最高次项系数。

对于:

\[A(x) = a_0 + a_1x + a_2x^2 \]

有:

A(infinity) = a2

其他几个点也很直观:

A(0)  = a0
A(1)  = a0 + a1 + a2
A(-1) = a0 - a1 + a2
A(2)  = a0 + 2a1 + 4a2

\(B(x)\) 也做同样的事情:

B(0)  = b0
B(1)  = b0 + b1 + b2
B(-1) = b0 - b1 + b2
B(2)  = b0 + 2b1 + 4b2
B(infinity) = b2

注意,取值过程里虽然出现了 \(2a_1\)\(4a_2\) 这样的写法,但这不是递归意义上的“大整数乘法”。因为 2 和 4 是固定小常数,它们通常可以通过移位和加法完成。

第二步:逐点相乘

求完值之后,我们得到若干组点值。然后在相同点上分别相乘:

C(0)        = A(0) * B(0)
C(1)        = A(1) * B(1)
C(-1)       = A(-1) * B(-1)
C(2)        = A(2) * B(2)
C(infinity) = A(infinity) * B(infinity)

这里一共做了 5 次乘法。

需要特别注意的是,这里的“乘法”不是 CPU 的单条机器乘法指令,而是 5 次规模更小的大整数乘法。每个参与相乘的数,长度大约是原来的三分之一,再加上一点由求值带来的常数级增长。

如果直接拆成 3 块做普通分块乘法,本来需要 9 次块乘法:

a0*b0, a0*b1, a0*b2
a1*b0, a1*b1, a1*b2
a2*b0, a2*b1, a2*b2

Toom-3 的关键是:用加减、移位、乘以小常数和插值,换掉其中一部分昂贵的大整数乘法,把 9 次子乘法压缩成 5 次子乘法。

对于大整数来说,乘法通常比加减法贵得多。所以用更多线性级别的操作,换更少的递归乘法,通常是划算的。

image

第三步:插值

经过逐点相乘之后,我们知道了 \(C(x)\) 在几个点上的值。

但是最终需要的是 \(C(x)\) 的系数,也就是要恢复:

\[C(x) = c_0 + c_1x + c_2x^2 + c_3x^3 + c_4x^4 \]

这个过程就是插值。

四次多项式可以由 5 个不同点上的取值唯一确定,所以我们可以从:

C(0), C(1), C(-1), C(2), C(infinity)

恢复出:

c0, c1, c2, c3, c4

恢复出这些系数之后,再把 \(x = \beta\) 代回去:

\[AB = c_0 + c_1\beta + c_2\beta^2 + c_3\beta^3 + c_4\beta^4 \]

这样就得到了原来两个大整数的乘积。

这里的乘以 \(\beta^i\) 主要对应把系数块放到正确的位置上,并做进位归一化,也不是重新做几次普通意义上的大整数乘法。

image

伪代码

如果把上面的流程写成伪代码,大致是这样:

toom3_mul(A, B):
    split A into a0, a1, a2
    split B into b0, b1, b2

    evaluate:
        p0   = a0
        p1   = a0 + a1 + a2
        pm1  = a0 - a1 + a2
        p2   = a0 + 2a1 + 4a2
        pinf = a2

        q0   = b0
        q1   = b0 + b1 + b2
        qm1  = b0 - b1 + b2
        q2   = b0 + 2b1 + 4b2
        qinf = b2

    pointwise multiply:
        r0   = p0 * q0
        r1   = p1 * q1
        rm1  = pm1 * qm1
        r2   = p2 * q2
        rinf = pinf * qinf

    interpolate:
        recover c0, c1, c2, c3, c4 from r0, r1, rm1, r2, rinf

    recombine:
        return c0 + c1*beta + c2*beta^2 + c3*beta^3 + c4*beta^4

上面伪代码里,真正昂贵的递归大整数乘法,主要是这 5 行:

r0   = p0 * q0
r1   = p1 * q1
rm1  = pm1 * qm1
r2   = p2 * q2
rinf = pinf * qinf

Toom-k 的一般形式

更一般地,如果把整数拆成 \(k\) 块,那么对应的多项式次数是 \(k - 1\)

两个 \(k-1\) 次多项式相乘,乘积多项式的最高次数是:

\[2k - 2 \]

因此,它一共有:

\[2k - 1 \]

个系数。

为了恢复这个乘积多项式,我们需要 \(2k - 1\) 个取值点,也就需要做 \(2k - 1\) 次规模更小的子乘法。

\(k\) 固定,并且取值、插值、搬移、进位等额外操作都近似为线性级别的前提下,可以粗略写出递推式:

\[T(n) = (2k - 1)T(n/k) + O(n) \]

根据主定理,它的复杂度约为:

\[O(n^{\log_k(2k-1)}) \]

几个常见算法可以粗略对比如下:

普通乘法:O(n^2)
Karatsuba:拆成 2 块,做 3 次子乘法,指数约 1.585
Toom-3:拆成 3 块,做 5 次子乘法,指数约 1.465
Toom-4:拆成 4 块,做 7 次子乘法,指数约 1.404

从理论上看,\(k\) 越大,复杂度指数越低。

但是,\(k\) 变大之后,取值点更多,插值更复杂,中间结果也更多,常数开销会明显增加。因此真实的大整数库不会盲目使用很大的 \(k\),而是会根据整数规模在普通乘法、Karatsuba、Toom-Cook、FFT 或 NTT 类算法之间切换。

总结

Toom-Cook 的整体思路可以概括为:

大整数太长,直接乘很慢
       |
       v
把大整数按 beta 拆成几块
       |
       v
把这些块看成多项式系数
       |
       v
在几个简单点上求值
       |
       v
在相同点上逐点相乘
       |
       v
通过插值恢复乘积多项式
       |
       v
把 x = beta 代回去,得到最终整数结果

其中最关键的洞察是:大整数乘法可以转化成多项式乘法,而多项式乘法可以通过“取值 + 逐点相乘 + 插值”来完成

Toom-Cook 并不是让乘法消失,而是把许多直接的分块乘法,变成更少次数的子问题乘法。

它付出的代价是更多加减法、移位、乘以小常数、插值和进位处理。由于这些操作通常比同规模的大整数乘法便宜,所以在数字足够大时,这种交换是划算的。

从这个角度看,Toom-Cook 和 FFT 乘法确实有某种共同精神:它们都不是直接在系数上硬乘,而是换一个表示空间,让乘法在新的表示中更容易完成。