为了让一次除法正确,Futhark 让所有除法都变慢了一点
来源:futhark-lang.org — 2026-10-14
📋 概述
补码表示是不对称的:最负的数没有对应的正数,8 位下是 -128 对 127。这个古怪之处在带符号整数除法上会咬人——数学上 x/-1 应得 -x,但当 x 是最负数时这个结果无法表示。对 32 位整数而言,这意味着 2⁶⁴ 种可能输入里有一种是无法正确表示的,这也就是标题里那个夸张百分比(0.000000000000000000542%)的来源,而 Futhark 编译器最近正是为它动刀。文章解释真正的麻烦来自 C:Futhark 最重要的后端生成 C 代码,可读、可调试、可移植,还能让别的语言通过 C API 调用;但 C 里带符号整数溢出是未定义行为,编译器可以假设它永不发生。Futhark 的语义却是溢出回绕。C 又恰好规定无符号溢出行为良好,于是 Futhark 用无符号 C 类型表示所有整数(i64 变 uint64_t),在无符号类型上做算术,从而绕开未定义行为。文章随后讲清了这个方案在除法上的破口,以及修复的性能代价。
🔑 核心要点
- 问题的量级被算得很干脆:32 位带符号整数下,2⁶⁴ 种输入里只有一种(x 为最负数、除数为 -1)无法表示正确结果
- 麻烦的根源是 C 而非 Futhark:C 里带符号整数溢出属于未定义行为,编译器可以据此假设它永不发生,而 Futhark 的语义是回绕
- 常用绕法是把所有整数用无符号 C 类型表示(i64 → uint64_t),因为 C 明确保证无符号溢出行为良好
- 文章面向语言实现者:结论是修这一个极端 case 会让所有除法都变慢,代价与收益的比例需要读者自己判断
- 选择用 C 作为后端也有明确取舍清单:易调试、依赖少、可被他语言通过 C API 调用,代价是容易生成微妙错误的 C 代码
💡 金句
Making all divisions slower to fix a bug in 0.000000000000000000542% of cases
👍 0
👎 0
← 返回 Lobsters 首页