x86-64アーキテクチャ(現代のIntel/AMDのほとんどのCPU)で、整数除算 (idiv) が 浮動小数点除算 (divss / divsd) よりも明らかに遅い(多くの場合5〜15倍遅い)主な理由は以下の通りです。
現代のx86-64 CPUにおける除算レイテンシの目安(2024–2026年頃のCPU)
| 演算 | 命令例 | レイテンシ(サイクル) | スループット(1サイクルあたり) | 備考 |
|--------------------------|--------------|--------------------------|----------------------------------|------|
| 32bit整数除算 | idiv r32 | 9〜18 | 約0.25〜0.5 | 非常に遅い |
| 64bit整数除算 | idiv r64 | 18〜40(最悪で90超も) | 約0.1〜0.25 | 特に遅い |
| float 除算 (単精度) | divss | 4〜11 | 0.5〜1 | SSE |
| double 除算 (倍精度) | divsd | 4〜14 | 0.5〜1 | SSE/AVX |
| float 除算 (AVX512) | vdivps | 4〜12 | 高い | 最新世代で優秀 |
(※ Skylake以降、Ice Lake、Alder Lake、Zen 3〜Zen 5 などの実測値の範囲)
なぜ整数除算がこんなに遅いのか?(主な理由まとめ)
仮数部のビット幅が違う
32bit整数 → 最大32ビット(符号ありなら実質31ビット)の除算
float → 仮数部は23〜24ビット(暗黙の1ビット込み)
→ 除算器が処理しなければならないビット数が少ない → 早く終わる
指数部の処理が圧倒的に安い
浮動小数点:指数部の除算は引き算1回だけ(固定コスト)
整数:指数という概念がない → 全体を高精度で割らないといけない
現代CPUは浮動小数点除算を「乗算+ニュートン・ラプソン法」で高速化している
FP除算のほとんどは「1/x の近似値 × x で割る数」を使って高速化
この近似値生成に専用回路(rcp系命令)が存在する
整数除算にはこのような高精度な初期近似回路がほとんど無い(一部の最新CPUを除く)
整数除算は正確性が厳格に要求される
浮動小数点:最後の1〜2ビットの丸め誤差は許容される
整数:完全に正確でなければならない → 補正処理が重い
よくある勘違いポイント
「浮動小数点演算は遅い」というのは昔の話(1990〜2000年代前半)
現在は乗算・加算に関しては整数とほぼ同等かむしろ浮動小数点のほうが並列性が高い
除算だけは今でも浮動小数点のほうが明らかに有利(特にfloat)
実際のコードでの落とし穴
`cpp
int a = 1000000000;
int b = 777777;
int c = a / b; // ← 遅い (idiv)
// 速くしたい場合の現実的な選択肢
float af = (float)a;
float bf = (float)b;
int c_fast = (int)(af / bf + 0.5f); // 注意!丸め誤差に気をつける
// もっと正確にしたいなら
int64_t c64 = (int64_t)a * 1000000000LL / b; // 乗算を先にやる手法
`
結論(2026年現在)
「intの除算」より「floatの除算」のほうが明らかに速い
→ 主に「仮数ビット幅が少ない」「指数処理が激安」「専用高速近似回路がある」ため
ただし「結果の正確さ」「丸め誤差」「オーバーフロー」「NaN/infの扱い」には十分注意が必要です。
速度を最優先する場面ではfloat除算+適切な丸め処理が現実的な最適解になるケースはかなり多いです。