Ryū (最短往復の float→文字列変換)

IEEE-754 浮動小数点数を、パースし直すと同じビット列に戻る中で最短の10進文字列に変換するアルゴリズム(Ulf Adams, “Ryū: fast float-to-string conversion”, PLDI 2018)。固定長整数演算だけで「最短かつ往復保証」を達成し、多倍長への fallback を持たない点が新しかった — 当時の最速だった Grisu3 比で約3倍。

何を解くか — 最短往復

float を印字するとき何が「正しい」か。各有限 float は、それに丸められる実数の half-ulp 区間(両隣の float との中点で挟まれる帯)を持つ。最短往復問題は「その区間に入る、最も桁数の少ない10進数」を選ぶこと。0.1(2進で正確に表せない)の候補:

条件は2つ同時に効く — ①往復(read-back で同一ビット)②最短(桁数最小)。丸めは round-to-nearest, ties-to-even に整合させる。

どう動くか — fallback 無しの鍵

古典 Dragon4 は多倍長(bignum)演算で正確だが遅い。Ryū の洞察は「結果の先頭数桁しか要らないなら、巨大な乗算は不要」(ulfjack README)。

系譜 — Dragon 一族

アルゴリズム出典位置づけ
Dragon4Steele & White, PLDI 1990最短・正確だが多倍長で遅い。命名の祖
Grisu(2/3)Loitsch, PLDI 2010整数で高速。Grisu3 は ~0.5% を Dragon4 に fallback
ErrolAndrysco ら, POPL 2016常に正しい高速法。Grisu3 比 2×
RyūAdams, PLDI 2018fallback 無しで最短。Grisu3 比 ~3×。固定長整数のみ
SchubfachGiulietti, ~2018/2021鳩の巣原理(独 Schubfach)。Java(JDK19+)が採用
DragonboxJeon, 2020–Schubfach 系。現状 Ryū と同等〜上回る

命名は全部ドラゴン由来: Dragon4 → Grisu(漫画の小さな竜) → Ryū(日本語の竜) → Dragonbox。作者本人いわく「White と Steele のは Dragon。同じ系譜で日本語の dragon = Ryu にした」。

性能と現在地

採用状況(2026 時点)

言語/実装最短変換備考
MSVC <charconv> std::to_charsRyū / Ryū printfMicrosoft STL が Ryū 由来
Rust エコシステムdtolnay の ryu クレート(serde_json 等)std/core は Ryū でなく Grisu+Dragon fallback(flt2dec)。最短になるのはこちらでも同じ
Go旧 Ryū → Dragonbox(2025-11〜)固定精度の Ryū-printf は維持
JavaSchubfach(JDK19+)旧 Double.toString は別法で非最短だった

→ よくある誤解「Rust = Ryū」は不正確。Rust std は Grisu+Dragon で、Ryū は外部 ryu クレートとして普及している(だから 0.3_f64.to_string() が "0.3" になるのは std の Grisu+Dragon の働き)。

変種: Ryū printf

固定精度版(“Ryū Revisited: Printf Floating Point Conversion”, Adams, OOPSLA 2019)。base Ryū が桁数を自分で決める(最短)のに対し、Ryū printf は呼び出し側が指定した桁数で %f/%e/%g を出す。任意基数にも一般化。既存 printf 実装比で 3.8〜55×(glibc ~15×、musl ~4×、MSVC ~9×、macOS libc ~24×)。

押さえどころ(カード化候補)

関連

Graph