はじめに
このガイドでは、空の MoonBit プロジェクトから Luna-Flow/floating で正しい最初の結果を得るまでを案内します。パッケージの選択、インストール、値の構築、精度と失敗の報告方法の選択、そして結果の読み方を扱います。すべての例は現在のブランチに対してコンパイルされます。
数値ドメインを選ぶ
パッケージは、入力の表記ではなく、プログラムが必要とする意味論によって選んでください。
| 必要なもの | パッケージ | 主な型 | 結果 |
|---|---|---|---|
| 任意精度の二進値、IEEE 754 二進形式 | bin_float | BinFloat | 値、または BinaryContext のもとでの (value, BinaryFlags) |
| IEEE 754 十進算術と decimal32/64/128 交換形式 | decimal | Decimal | 値、または DecimalContext のもとでの (value, DecimalFlags) |
| スティッキーなステータスとトラップを備えた General Decimal Arithmetic | decimal_gda | Decimal | 次の GdaContext を伴う GdaOutcome[Decimal] |
| 実数の結果の認証済み包含区間(IEEE 1788) | ball_float | BallFloat, BallFloatDecorated | 区間、または BallContext のもとでの (interval, BallFlags) |
| 最初のエラーで停止する二進パイプライン | bin_float_checked | BinFloatResult | ラッパー内の Result[BinFloat, ArithmeticError] |
| フラグを蓄積する IEEE 十進パイプライン | decimal_checked | DecimalChecked | 定義済みの値と、最新および蓄積された DecimalFlags |
| トラップで停止する GDA パイプライン | decimal_gda_checked | GdaDecimalChecked | 受け渡される一つの GdaOutcome[Decimal] |
| 最初のエラーで停止する区間パイプライン | ball_float_checked | BallFloatResult | ラッパー内の Result[BallFloat, ArithmeticError] |
| パッケージをまたいだ値の比較 | semantic | SemanticScalar, SemanticInterval | メタデータを意図的に捨てた厳密な有理数 |
def は、これらすべてが共有する小さな語彙(Sign、PartialOrder、Floating トレイト、再エクスポートされた arithmetic の型)を保持します。numeric_expr と frontend/* はパーサと適合性検証ツールのためのものです。internal/*、cli/*、consistency、doc_examples、bench/* はリポジトリの基盤であり、アプリケーションの依存先ではありません。すべてのパッケージはマニュアルの概要に一覧があります。
インストールとインポート
MoonBit ツールチェーン 0.10 以降(moonc ≥ 0.10)が必要です。モジュールを追加し、丸めモードやコンテキストを自分で名指しする場合は Luna-Flow/arithmetic も追加します。
moon add Luna-Flow/floating@0.8.0
moon add Luna-Flow/arithmetic
moon.pkg では使用するパッケージだけをインポートします。
import {
"Luna-Flow/arithmetic" @lf_arith,
"Luna-Flow/floating/bin_float",
"Luna-Flow/floating/decimal",
"Luna-Flow/floating/ball_float",
}
インポートはファイルではなくパッケージを指定します。moon.pkg を持つ各ディレクトリが一つのパッケージであり、そのファイルは一つの名前空間を共有します。慣例として、このマニュアルでは Luna-Flow/arithmetic を @lf_arith、Luna-Flow/luna-generic を @lf_alg としてインポートします。
値を構築する
BinFloat は精度を持つ厳密な二進有理数 です。Decimal は で、リテラルの量子 を記憶します。BallFloat は二進の端点を持つ区間です。
///|
test "first values" {
// 3 * 2^-1 at 53 bits of precision.
let binary = @bin_float.BinFloat::make(
@bin_float.BinCoeff::from_uint64(3UL),
-1,
53,
)
inspect(binary, content="3p-1")
inspect(binary.to_shortest_string(), content="1.5")
// Parsing keeps significant trailing zeros.
let price = @decimal.Decimal::from_string("12.3400").unwrap()
inspect(price, content="12.3400")
inspect(price.quantum(), content="-4")
// Every real number from 1 through 2.
let interval = @ball_float.BallFloat::from_bounds(
@bin_float.BinFloat::from_int(1),
@bin_float.BinFloat::from_int(2),
)
inspect(interval.contains(binary), content="true")
}
BinFloat は厳密な形式 <coefficient>p<exponent> で出力されます。十進テキストには to_shortest_string または to_decimal_string_ctx を使用してください。十進数に対して normalized() を呼ぶのは、そのコホートを捨てたい場合だけにしてください。
その他のコンストラクタ: BinFloat::from_int、from_double、from_string と from_string_ctx(正しく丸められた十進パース)、from_hex。Decimal::from_int、from_string、from_string_ctx。BallFloat::from_int、from_double、exact、from_bounds。コンストラクタはオプションの precision を取ります。BallFloat::from_int のデフォルトは 16 ビットなので、binary64 相当の端点が必要な場合は precision=53 を渡してください。
コンテキストを選ぶ
通常の演算子(+、-、*、/ および add、mul、…)は、オペランドの精度で最近接偶数丸めを行い、実質的に無制限の指数範囲で動作し、ステータスを破棄します。精度、指数範囲、丸め方向、極小性、ステータスフラグが結果の一部となる場合は、明示的なコンテキストとともに *_ctx 形式を使用してください。
///|
test "contextual arithmetic" {
let ctx = @bin_float.BinaryContext::binary64()
let (third, flags) = @bin_float.BinFloat::from_int(1).div_ctx(
@bin_float.BinFloat::from_int(3),
ctx,
)
inspect(third.to_shortest_string(), content="0.3333333333333333")
inspect(flags.inexact(), content="true")
// The same quotient rounded upward lands one ulp higher.
let up = @bin_float.BinaryContext::binary64(rounding=RoundTowardPositive)
let (high, _) = @bin_float.BinFloat::from_int(1).div_ctx(
@bin_float.BinFloat::from_int(3),
up,
)
inspect(high.sub(third) == third.ulp(), content="true")
let decimal_ctx = @decimal.DecimalContext::decimal64()
let (q, decimal_flags) = @decimal.Decimal::from_int(1).div_ctx(
@decimal.Decimal::from_int(3),
decimal_ctx,
)
inspect(q, content="0.3333333333333333")
inspect(decimal_flags.contains(@decimal.Inexact), content="true")
}
コンテキストは不変の値であり、ライブラリ内でグローバルな丸めモードを読むものはありません。IEEE のコンテキストは一つの演算のフラグを返し、それを自分で combine します。一方、GDA のコンテキストは結果とともに受け渡されます。すべての GdaOutcome は次のコンテキストを返し、そのステータスにフラグが蓄積されます。
失敗モデルを選ぶ
ライブラリは意図的に複数の失敗チャネルを公開しています。呼び出し側が観測すべき内容に合うものを選んでください。
Decimal::from_stringのような単純なコンストラクタからのOption。不正な入力に診断情報が不要な場合に使います。- checked 演算(
div_checked、sqrt、compare_checked、from_string、try_*_ctx初等関数)からのResult[T, ArithmeticError]。 - 定義済みの結果に付随する
BinaryFlags、DecimalFlags、BallFlags。 - トラップが発火しても GDA で定義された結果を保持する
GdaOutcome[T]。 - パイプラインのラッパー:
BinFloatResultとBallFloatResultは最初のエラーで停止します。DecimalCheckedは定義済みの NaN と無限大の結果を保持し、フラグを蓄積します。GdaDecimalCheckedはトラップで停止し、その結果を保持します。 - Empty、Entire、NaI。これらはエラーではなく区間の値です。
///|
test "pipelines" {
let failed = @bin_float_checked.BinFloatResult::from_int(-4).sqrt()
inspect(failed.is_err(), content="true")
let total = @decimal_checked.DecimalChecked::parse(
"1",
@decimal.DecimalContext::decimal64(),
)
.div(@decimal.Decimal::from_int(3))
.mul(@decimal.Decimal::from_int(3))
inspect(total.value(), content="0.9999999999999999")
// Accumulated over the pipeline versus raised by the last step.
inspect(total.flags().contains(@decimal.Inexact), content="true")
inspect(total.raised().contains(@decimal.Inexact), content="false")
}
これらのチャネルを一つの例外型や一つの Result にまとめないでください。標準が観測可能にしている意味論が失われます。
結果を正しく読む
- 符号付きゼロ、無限大、quiet NaN と signaling NaN、NaN のペイロードはスカラーで観測可能です。
compare、<、ソートは全前順序を用います。そこではすべての NaN が互いに等しく、すべての数より上にあり、 です。IEEE の意味論が必要な場合は、compare_checked、bin_floatの quiet / signaling 述語、またはtotal_order*関数を使用してください。BinFloatとBallFloatの==は表現を比較します(ゼロの符号と精度を含む)。Decimalの==は値を比較します。二進値の数値的な等価性にはcompare(a, b) == 0を使用してください。BallFloatにはスカラーの順序ではなく、包含関係と集合の関係(contains、subset、definitely_lt、…)があります。結果が正しいとは、それが厳密な結果を包含することです。区間の狭さは別の品質です。SemanticScalarはパッケージをまたいで数学的な値を比較し、精度、量子、符号付きゼロ、ペイロード、装飾、フラグを捨てます。
次に読むもの
- 数値意味論では、丸め、ulp、フラグ、量子、符号付きゼロ、NaN、包含区間を、その導出とともに定義しています。
- アーキテクチャでは、パッケージのレイヤーと認証付き初等関数を説明しています。
- 検証では、ゲートと各適合性の主張の正確な範囲を示しています。
- 各パッケージにはチュートリアル、API リファレンス、設計ページがあります。まずは
bin_floatチュートリアル、decimalチュートリアル、またはball_floatチュートリアルから始めてください。