实现 FMA 却揪出 C 与 Rust 标准库的隐藏 bug
来源: shnatsel.github.io — 2026-08-31
概述
作者为 fearless_simd 实现软件版 FMA(fused multiply-add,一次舍入算出 a*b+c)时,循着一篇 2008 年用 Coq 形式化验证过的论文,用 f64 算完再舍入回 f32。正当他以为大功告成,一位陌生网友贴出一组让他的实现与硬件结果分道扬镳的输入——问题出在他漏掉了对亚正常数(subnormal)的特殊处理。深入排查后他发现:Rust 标准库内置的 f32::mul_add 与 std::simd 存在完全相同的 bug,而它又源自 musl libc 的 fmaf.c,后者版权标注又追溯到 FreeBSD。这段带着 bug 的代码在标准库与工具链里被复制粘贴了二十年。作者逐一修复并提交 PR,还顺带发现 32 位 ARM 上 nightly 的 f128 类型因 rustc ABI bug 彻底错乱。他提醒:在没有硬件 FMA 的旧 Intel 与国产 Hygon 芯片上,这个错误舍入虽只差一个最低有效位,却可能被放大,让确定性模拟在不同机器上分道扬镳。
核心要点
作者把 2008 年一篇有 Coq 形式化证明的论文算法搬进 fearless_simd,实现比 std::simd 快 5 倍
一位素未谋面的网友贴出反例,暴露作者漏掉了对亚正常数(subnormal)的特殊处理
Rust 标准库内置 f32::mul_add、std::simd 以及源自 FreeBSD 的 musl libc fmaf.c 都带有同一处舍入 bug
这段错误代码在标准库与各平台工具链里被复制粘贴了约二十年
无硬件 FMA 的旧 Intel(无 AVX2)与国产 Hygon 芯片才会触发,64 位 ARM 不受影响,但确定性模拟可能因此分道扬镳
金句
Moments like these are why I love open source. I have no idea where he came from or how he even found this PR.(正是这样的时刻让我热爱开源——我完全不知道他从哪来,又是如何找到这个 PR 的。)
👍 0
点赞
👎 0
沉底
返回 Lobsters 首页