はじめに

以前「Rustのsoftfloatライブラリ比較」という記事でRustにおけるソフトウエア実装の浮動小数点数演算ライブラリを紹介しました。このときに気づかなかったのですが、実はもう一つ有力なライブラリがあったのを最近発見しましたので紹介します。

rustc_apfloat

これはRustコンパイラ内部で使われている任意精度の浮動小数点数演算ライブラリです。(apfloatはArbitrary Precision Floatの略です)

なぜRustコンパイラ内でこのようなライブラリが必要かというと、主にconstな浮動小数点数演算を行うためです。
一般的に浮動小数点数演算はLLVM-IRを経由して各アーキテクチャの機械語に変換され、CPUで実行されます。
基本的にCPUが実装する浮動小数点数演算はIEEE-754という規格に従っていますが、規格で定義されていない部分も少しあり、全てのCPUから全く同じ結果が得られるわけではありません。

もしconstな浮動小数点数演算の結果がCPU毎に違っていたとすると、その演算結果をconst genericsに適用して型を生成したときに、CPUによって違う型が生成されてしまう可能性があり、クロスコンパイルのバイナリとネイティブコンパイルのバイナリの相互運用性に問題が生じる可能性があります。

そこでコンパイラ内でソフトウエア実装の浮動小数点数演算を用意して、それを使ってconst計算を行うことで任意のアーキテクチャで全く同じ演算結果を保証できるようにしました。これがrustc_apfloatです。
これはLLVMのAPFloatをRustに移植したもので、unsafeなしのpure-Rustコードになっています。

具体的な経緯は以下のPRにあります。

基本的にコンパイラの実装で使われているのでそのまま依存関係に含めることはできませんが、全く同じものをクレートにした人がいるので普通に使うことができます。

また、このrustc_apfloatを正式にクレート化しようという話もあります。元がLLVMのコードなので現在はライセンスの取り扱いについて議論しているところのようです。

使い方

使い方は以下のような感じです。IEEE-754準拠のHalf/Single/Double/QuadやPowerPCのDoubleDoubleが用意されています。内部表現は全てu128です。

use rustc_apfloat::{ieee::Half, Float, Round};
let a = 0x1234;
let b = 0x7654;
let a = Half::from_bits(a as u128);
let b = Half::from_bits(b as u128);
let d = a.add_r(b, Round::NearestTiesToEven);
assert_eq!(d.value.to_bits(), 30292);

パフォーマンス

以前測定したのと同じ環境で測定してみました。

image.png

縦軸は対数なのでご注意ください。前回最も早かったC実装のsoftfloat-sysと比べると10倍くらいは遅いですが、rugとは同等ですし、十分使える範囲だと思います。pure-Rustということで、WASMなどCバインディングを使いにくい環境に適しているのではないでしょうか。

广告
将在 10 秒后关闭
bannerAds