Rust实现《从数学到泛型编程》乘法算法,基准测试结果与预期不符求助
我完全懂这种困惑——跟着经典书里的优化步骤一步步敲代码,结果基准测试出来的结果跟书里说的完全反过来,那种抓耳挠腮的感觉太真实了。结合Rust的编译器特性和《从数学到泛型编程》里算法的设计背景,咱们来拆解几个最可能的原因:
1. Rust编译器的自动优化可能“盖过”了手动优化的优势
书中的mul4这类高度优化的算法,很多是针对早期编译器或特定硬件架构设计的手动汇编级优化。但Rust的rustc基于LLVM,在-O3优化等级下,会自动做循环展开、指令重排、甚至直接把简单乘法替换成硬件原生指令。
比如,如果你的测试用例是普通的64位小整数乘法,LLVM可能直接把mul4里复杂的位拆分、分治逻辑优化成一条mul指令,反而让手动优化的额外分支和操作变成冗余开销,拖慢了速度。
你可以试试给每个乘法函数加上#[inline(never)]标记,强制编译器不内联这些函数,看看测试结果会不会更贴近书中的预期——不过这只是排查手段,实际生产中还是要相信编译器的优化能力。
2. 基准测试的写法可能有“坑”
Rust的cargo bench如果用得不对,很容易出现结果失真的情况,常见的问题包括:
- 测试数据不匹配:书中的
mul4是为大整数场景设计的优化,但你可能用了小整数测试,这时位操作的优势完全体现不出来,反而因为额外逻辑拖慢速度; - 被编译器常量折叠:如果你的测试用的是编译期常量,LLVM会直接提前算出结果,根本不会运行你的乘法函数;
- 循环被优化掉:如果基准测试的循环没有保留计算结果,编译器可能直接把整个循环删掉。
解决这些问题的正确姿势是用criterion库搭配black_box,防止编译器优化掉核心计算逻辑,示例代码如下:
use criterion::{criterion_group, criterion_main, Criterion}; use std::hint::black_box; // 你的mul4实现 fn mul4(a: u64, b: u64) -> u64 { // ... 书中的实现代码 ... } fn bench_mul4(c: &mut Criterion) { c.bench_function("mul4", |b| { // 用black_box包裹输入,避免编译器提前计算 b.iter(|| mul4(black_box(0xDEADBEEF), black_box(0xC0FFEE))) }); } criterion_group!(benches, bench_mul4); criterion_main!(benches);
3. 硬件架构的差异导致算法优势失效
书中的mul4可能是针对32位CPU或者老式x86架构设计的,但你现在用的可能是64位CPU(比如AMD64)甚至ARM架构。不同架构下,位操作、移位指令的周期数完全不同:64位CPU的原生乘法指令可以直接处理64位整数,而mul4为了模拟高精度乘法做的拆分操作,反而比硬件指令多走好几步。
你可以试试在32位目标下编译测试(比如cargo bench --target i686-unknown-linux-gnu),看看mul4的性能会不会回升。
4. 算法的适用场景被你忽略了
书中的mul4是为无符号大整数乘法(比如超过原生寄存器宽度的数)设计的分治优化,但如果你的测试用的是原生宽度的整数(比如u64),那硬件的原生乘法指令肯定比手动拆分的位操作快得多。只有当你处理的数超过CPU寄存器宽度时,mul4这类算法的优势才会体现出来。
比如,如果你测试两个128位整数的乘法,用mul4的分治思路拆分计算,应该会比直接模拟大整数乘法快,但测试u64的话,就完全没必要用这种复杂算法了。
内容的提问来源于stack exchange,提问作者lwi

