8月20日、Rust Release Teamが「Announcing Rust 1.98.0」と題した記事を公開した。
Rust 1.98.0の目玉は、C/C++の -ffast-math に相当する浮動小数点最適化を、未定義動作なしに安全に利用できるようにする代数的演算メソッドの安定化だ。数値計算やゲームエンジン、機械学習推論など、浮動小数点のスループットが問題になる領域でRustはC++に対して「最適化の自由度が低い」という弱点を抱えてきた。その弱点が標準ライブラリレベルでついに解消される。加えて、itoaクレートと同等性能の整数フォーマットAPIも標準化され、実用上の恩恵は小さくない。
代数的浮動小数点メソッド(Algebraic floating-point methods)
C/C++では -ffast-math コンパイラフラグを使うことで、浮動小数点演算の厳密な順序をコンパイラが自由に並び替え、SIMDベクトル化などの積極的な最適化を引き出せる。しかしRustにはこれに相当する仕組みがなく、数値計算分野での採用を妨げる要因の一つとなっていた。PyTorchやJAXのようなMLフレームワークがC++で書かれ続ける背景には、こうした最適化の柔軟性の差もある。
今回安定化されたのは、f32・f64への代数的演算メソッド群だ。algebraic_add・algebraic_sub・algebraic_mul・algebraic_div・algebraic_rem が追加された。これらは「実数の代数的性質(結合法則・分配法則など)が成立する」とコンパイラに伝えることで、最適化の自由度を大幅に引き上げる。
浮動小数点の加算は結合法則が成立しない。a + b + c + d は丸め誤差の関係上、通常は ((a + b) + c) + d の順に評価しなければならない。しかし algebraic_add を使うと、コンパイラは (a + b) + (c + d) のように部分和を並列に評価できるようになる。これによりループのSIMDベクトル化が促進され、スループット向上が期待できる。
重要な注意点として、最適化の具体的な内容はコンパイラが決定するため結果は非決定的になりうる。実行環境や最適化レベルによって計算結果が変わる可能性がある。ただし、これらのメソッドは未定義動作(UB)を一切引き起こさない点で -ffast-math より安全だ。-ffast-math はNaN・Infinityの取り扱いすら変えてしまうことがあり、デバッグが困難なバグの温床になりうるが、Rustの代数的メソッドはその点で線引きが明確になっている。詳細はライブラリドキュメントおよびAPIチェンジプロポーザルを参照のこと。
整数のバッファ付きフォーマット(Buffered integer formatting)
すべてのプリミティブ整数型に format_into メソッドが追加された。&mut NumBuffer<Self> を引数に取り、その型のどんな値でも収まるスタック上のバッファに十進数フォーマットの結果を書き込む。戻り値はそのバッファのライフタイムを借用した &str だ。
従来の format! や write! マクロは内部で動的ディスパッチが発生するため、ホットパスでの整数→文字列変換には itoa クレートが広く使われてきた。itoa はRustの主要コントリビューターであるdtolnay氏が作成したクレートで、その氏自身が整備したitoa-benchmarkによる計測では、format_into のパフォーマンスが itoa クレート自体と同等水準に達したという。整数フォーマットのためだけに外部クレートを依存関係に追加する必要がなくなる可能性が高い。
ManuallyDropとBoxの相互作用の保証
unsafe コードを書く開発者向けの重要な変更もある。Rust 1.96.0で修正済みのバグについて、今回のリリースで安定した動作保証がドキュメントに明記された。
問題となっていたのは以下のパターンだ。
let mut x = ManuallyDrop::new(Box::new(1));
unsafe { ManuallyDrop::drop(&mut x) }
let x = x;
1.96.0以前では、drop済みのBoxをManuallyDrop越しにムーブする操作がコンパイラに未定義動作と見なされる可能性があった。1.96.0でその挙動が修正され、今回のリリースでこの修正が将来にわたって維持されることが公式ドキュメントに明記された。unsafe コードの正しさを論証する際の根拠として使えるようになったことは、低レイヤーの実装者にとって大きい。背景となる仕様はRFC 3336(maybe-dangling)に詳しい。
その他の変更とアップデート方法
Rust本体、Cargo、Clippyの詳細な変更点はそれぞれのChangelogで確認できる。コントリビューターの一覧はthanks.rust-lang.orgで公開されている。
アップデートは以下のコマンドで適用できる。
$ rustup update stable
詳細はAnnouncing Rust 1.98.0を参照していただきたい。