mpfr_expr チュートリアル

このチュートリアルでは、GNU MPFR で計算した参照結果に対して bin_float を検査する方法を説明します。サポートされる行指向の形式は 3 つあります。MPFR 自身の平方根テストデータ、整数べき乗、初等関数マトリクスです。ファイルを文書に構文解析し、実行して、要約を読みます。コマンドラインランナーは mpfr_expr_cli です。

クイックスタート

moon.pkg にパッケージを追加します。

import {
  "Luna-Flow/floating/frontend/mpfr_expr",
}

53 ビット、最近接丸めで、1 つの平方根 2−1074⋅252=2−511\sqrt{2^{-1074} \cdot 2^{52}} = 2^{-511} を検査します。

///|
test "quick start" {
  let rows =
    #|# input_precision output_precision rounding input expected
    #|53 53 n 0x10000000000000p-1074 0x10000000000000p-563
    #|
  let document = @mpfr_expr.parse_sqrt_data("sqrt.txt", rows).unwrap()
  let summary = @mpfr_expr.execute_sqrt_data(document)
  inspect(summary.passed_cases(), content="1")
  inspect(summary.success(), content="true")
}

数値は 16 進の仮数と 2 進の指数で書きます。0x10000000000000p-1074 は 252⋅2−10742^{52} \cdot 2^{-1074} です。

日常的なタスク

フラグ付きの初等関数

初等関数の行は、関数名、出力の精度と丸め、オペランド、期待される結果、3 つの例外フラグ(inexact、invalid、ゼロ除算)を記述します。使わないオペランドは -(第 2 オペランド)と 0(整数オペランド)で書きます。

///|
test "elementary rows" {
  let rows =
    #|# mpfr-elementary-v1
    #|# op prec rnd x y n expected inexact invalid divbyzero
    #|exp 24 n 0x0p0 - 0 0x1p0 0 0 0
    #|ln 53 n 0x0p0 - 0 -inf 0 0 1
    #|sqrt 53 z -0x1p0 - 0 nan 0 1 0
    #|rootn 53 n 0x1bp0 - 3 0x3p0 0 0 0
    #|hypot 53 d 0x3p0 0x4p0 0 0x5p0 0 0 0
    #|
  let document = @mpfr_expr.parse_elementary_data("elem.txt", rows).unwrap()
  let summary = @mpfr_expr.execute_elementary_data(document)
  inspect(summary.total_cases(), content="5")
  inspect(summary.passed_cases(), content="5")
}

ln(0) = -inf はゼロ除算を発生させ、sqrt(-1) は NaN を返す無効演算です。どちらのフラグも検査の対象です。

整数べき

pow の行は、各数値を係数、2 進指数、符号に分けて記述します。

///|
test "integer power rows" {
  // (3 * 2^-1)^3 = 27/8 at 11 bits, exact
  let rows =
    #|11 n 3 -1 0 3 6c0 -9 0 0
    #|
  let document = @mpfr_expr.parse_pow_data("pow.txt", rows).unwrap()
  let summary = @mpfr_expr.execute_pow_data(document)
  inspect(summary.passed_cases(), content="1")
}

各フィールドは、精度、丸め、入力の係数(16 進数字)、入力の指数、入力の符号(1 は負)、整数の指数、期待される係数、期待される指数、期待される符号、inexact フラグです。ここで 0x6c0p-9 は 1728/512=27/81728/512 = 27/8 です。

失敗を読む

///|
test "a failing row" {
  let rows =
    #|# mpfr-elementary-v1
    #|exp 24 n 0x0p0 - 0 0x2p0 0 0 0
    #|
  let summary = @mpfr_expr.execute_elementary_data(
    @mpfr_expr.parse_elementary_data("bad.txt", rows).unwrap(),
  )
  let result = summary.results()[0]
  inspect(result.id(), content="exp:2")
  inspect(
    result.message(),
    content="elementary mismatch: expected 0x1p1 flags=false/false/false, actual 0x1p0 flags=false/false/false",
  )
}

ID は演算(または sqrt/pow)と行番号です。

構文解析エラー

不正な行はすべて行番号付きで報告され、文書は返されません。

///|
test "parse errors" {
  match @mpfr_expr.parse_sqrt_data("bad.sqrt", "53 53 x 0x1p0 0x1p0\n53 53\n") {
    Err(diagnostics) =>
      inspect(
        diagnostics.map(d => d.line().to_string() + ": " + d.message()).join("; "),
        content="1: invalid or unsupported MPFR data_check directive; 2: MPFR data_check row must contain five fields",
      )
    Ok(_) => fail("expected diagnostics")
  }
}

さらに進んで

  • コーパス。 just conformance run binary は、固定された MPFR の tests/data/sqrt ファイルとコミット済みの初等関数マトリクス testdata/bin_float/mpfr-4.2.2-elementary.txt を TestFloat と合わせて実行します。検証 を参照してください。初等関数データとべき乗データの生成器は tools/generate_mpfr_elementary_oracle.c と tools/generate_mpfr_pow_oracle.c です。
  • どのパーサが使われるか。 CLI は、ファイルが mpfr-elementary-v1 を含めば初等関数形式、input_coefficient_hex を含めばべき乗形式、それ以外は平方根形式を選びます。マーカーはコメント行に置いてください。

よくある落とし穴

  • 初等関数の行はエンコーディングではなく数値を比較します。 そこでは +0 と -0 は等しいとみなされ、任意の NaN が期待値 nan にマッチします。平方根とべき乗の行は、ゼロの符号を含めて BinFloat 全体を比較します。
  • 平方根のフラグは検査されません。 sqrt のデータ行は値だけを比較します。
  • 指数範囲はありません。 行は有界でないコンテキストで実行されます。オーバーフロー、アンダーフロー、非正規化数の範囲は存在せず、オーバーフローやアンダーフローを報告する初等関数やべき乗の行は失敗します。
  • 2 項演算には第 2 オペランドが必要です。 第 2 オペランドが - である初等関数の pow、hypot、atan2 の行はパーサには受理されますが、実行時に中断します。

次のステップ