
2026/08/11 14:48
整数除法を浮動小数点に移動させるのは容易である
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
現在のハードウェアは、整数除算(
div/mod)の遅延が高くスループットが低いという点で課題を抱えていますが、浮動小数点除算の方が高速です。このボトルネックを解決する新たな手法として、32ビット以内(双精度の場合)または16ビット以内(単精度の場合)の整数を浮動小数点数に変換し、標準的な丸めを用いて商と剰余を同時に計算する方法があります。このアプローチは極めて信頼性が高く、基数2におけるバイナリ演算では表可能な数値間に中間点がないため、複雑な「偶数への切り捨て」のような丸めルールを起動させることが不可能であり、単に「近傍への丸め」のみが適用されるため、ロジックが大幅に単純化されます。libdivideやコンパイラの最適化といった既存のソフトウェアは既知の除数に対して最適ですが、この手法は汎用アプリケーションにおいて、限られた精度内での頻繁な除算を処理する際に顕著なスループット向上をもたらします。実装には変換オーバーヘッドの管理(一部の x64 CPU では専用オペコードがない可能性がある)や、丸めモードや AVX-512 などの指令の扱いが必要となりますが、この戦略は現代的な浮動小数点ユニットの有効活用を図り、計算負荷の高いワークロードを加速させる一方で精度の低下を引き起こしません。本文
整数除算と剰余を浮動小数点演算で高速化する手法
1. 背景と目的
現在の CPU アーキテクチャにおいて、整数の除法・剰余演算は極めて遅く(高いレイテンシ、低いスループット)、逆に浮動小数点演算は高速である。そのため、一部の整数除算を浮動小数点計算へ置き換えることで性能向上が可能となるケースがある。
// 目標:整数除法 x / y と剰余 x % y を高速に求める
2. アルゴリズムの概要
53 ビット(倍精度)または 24 ビット(単精度)以内に収まる有符号・無符号整数 $x, y$ について、標準丸めモード(nearest-neighbor, ties-to-even)を使用し以下の操作を行う。
// d: 浮動小数点計算からの結果 (整数値として扱う) // m: 剰余の値 (整数値として扱う) // x, y: 入力整数 (無符号の場合を基準とする) d = trunc(x / y); // 浮動小数点除法で商を取得 (floor でも OK) m = -fma(d, y, -x); // fma 命令を使用し剰余を計算
注意:
(加算・乗算統合命令)の使用が必須である。fma
やtrunc
は、浮動小数点数から整数への変換に伴うコストがゼロとなる場合がある。floor- 本解説では扱いが難しい無符号整数を前提とするが、浮動小数点の性質上符号付絶対値として扱われるため留意が必要。
3. 実践的な注意点と制約
この手法の有効性は以下の要因に依存する。
- 丸めモードのコスト: 「負の方向への丸め(TOWARD_ZERO)」設定は可能だが、コントロールワードへのアクセスが高コストであることが多い。
- 一部のハードウェア(例:AVX-512 の
)では、遅延約 14 サイクルで特定丸めが可能。_mm_div_round_sd
- 一部のハードウェア(例:AVX-512 の
- 変換オーバーヘッド: 整数⇔浮動小数点の変換にはコストがかかる。(x86-64 では直接変換命令が不足する場合あり)
- 精度の限界: 浮動小数点精度 $p$ が利用可能な整数幅の上限を決定する。
- 倍精度 ($p=53$): 32 ビット整数対応 OK
- 単精度 ($p=24$): 16 ビット整数対応 OK
- より狭い位長であれば当然機能する。
- SIMD の活用: オーバーヘッドを均等化するために SIMD 演算が特に有効。
- 最適化の適用:
- 除数が定数の場合:コンパイラで削除される。
- 実行時固定除数かつ再利用回数が少ない場合:
などを用いるのが効率的。libdivide
4. 理論的根拠:同点(ties)の不存在
標準丸めモードは「最近傍丸め(ties-to-even)」だが、2 進浮動小数点算術において厳密な中間値(同点)は発生しない。 したがって、「同点」を考慮せず、「単純な最近傍丸め」のみで動作保証が可能である。
4.1 数式の導出
厳密な結果 $x/y$ を整数部 $n$ と小数部に分ける。 $$ \frac{x}{y} = n + \frac{a}{b} \quad (\text{ここで } b=y) $$ 明らかに $\frac{a}{b} \in [0, 1)$ である。
精度 $p$ の浮動小数点形式で除算を行う場合:
- 整数部(有効桁):$d = \lfloor \log_2(n) \rfloor + 1$ ビット
- 小数部のビット数:$r = p - d$
$r$ ビットの小数部分において、次の整数へ丸められるには「上への丸め」が必要であり、そのためには小数部が少なくとも $r+1$ 個の連続した 1(leading ones)を持つことが理論上の必要条件となる。
4.2 上限値の解析
$r$ ビットの範囲で、「1 に最も近い最大の値」を下限・上限で定義する。
- 下限関数:$\text{func_b_l}(r) = \frac{2^r - 1}{2^r}$ ($r$ 個の 1 を持つ最小の数)
- 上限関数:$\text{func_b_u}(r) = \frac{2^{r+1} - 1}{2^{r+1}}$
比較不等式: $$ \frac{2^{r+1}-2}{2^{r+1}-1} < \frac{2^{r+1}-1}{2^{r+1}} $$
この不等式より、上限が持つ連続する 1 の数は $r$ 個に限られる。つまり、必要な「$r+1$ 個の連続した 1」を達成することは不可能である。 したがって、同点ケースは発生せず、常に「最近傍丸め(ties-to-even)」として動作する浮動小数点除法の結果は、整数除法と完全に一致することを証明できる。
5. 除数による挙動の確認
いくつかの特定な除数をテストした結果:
- 除数が 1: 正確に一致。
- 除数が 2: 指数操作のみで処理され、丸め誤差なし。
- 除数が 3 ($r=1$): 最大剰余は 2。小数部 $2/3$ は整数未満のため、次の整数へ丸められない。
- 除数が {4, 5, 6, 7} ($r=2$): 厳密な値が
で始まるため、同点現象を誘発しない。.110x
6. まとめ
数学的な原理はシンプルであり、浮動小数点演算ユニットを用いることで整数除算の性能問題を解決できる。最悪ケースに対する検証コードは Godbolt を参照すること(binary32/binary64 両対応)。