frontend/testfloat_expr API

frontend/testfloat_expr 解析 Berkeley TestFloat 测试向量,并在 binary16、binary32、binary64 和 binary128 交换格式下针对 bin_float 执行它们。TestFloatSpec 描述生成向量文件时所用的函数、舍入模式、微小性(tininess)规则和精确性;parse_testfloat 读取向量,execute_document 运行它们。该包不进行任何 IO;运行器是 cli/testfloat_expr_cli。教程展示工作流程,设计页面规定通过规则。

在 moon.pkg 中导入该包:

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

函数规格

TestFloatOperation

TestFloatOperation 列出执行器支持的 TestFloat 函数。

pub(all) enum TestFloatOperation {
  Add
  Subtract
  Multiply
  Divide
  SquareRoot
  MulAdd
  Remainder
  RoundToInt
  ToInt32
  ToInt64
  ToUInt32
  ToUInt64
  Equal
  LessEqual
  Less
  EqualSignaling
  LessEqualQuiet
  LessQuiet
} derive(Eq, @debug.Debug)
构造子TestFloat 名称操作数bin_float 方法
Add, Subtract, Multiply, Divideadd, sub, mul, div2add_ctx, sub_ctx, mul_ctx, div_ctx
SquareRootsqrt1sqrt_ctx
MulAddmulAdd3fma_ctx
Remainderrem2remainder_ctx
RoundToIntroundToInt1精确时为 to_integral_exact_ctx,否则为 to_integral_value_ctx
ToInt32, ToInt64, ToUInt32, ToUInt64to_i32, to_i64, to_ui32, to_ui641带 exact~ 的 to_int_ctx、to_int64_ctx、to_uint_ctx、to_uint64_ctx
Equal, LessEqual, Lesseq, le, lt2equal_quiet, less_equal_signaling, less_signaling
EqualSignaling, LessEqualQuiet, LessQuieteq_signaling, le_quiet, lt_quiet2equal_signaling, less_equal_quiet, less_quiet

TestFloatSpec

TestFloatSpec 是一次 TestFloat 运行的配置。

pub struct TestFloatSpec {
  // private fields
} derive(Eq, @debug.Debug)

TestFloatSpec::parse

TestFloatSpec::parse(function_name, rounding, tininess?, exact?) 根据 TestFloat 名称构建一个规格。

pub fn TestFloatSpec::parse(String, String, tininess? : String, exact? : Bool) -> Result[Self, String]

function_name 的形式为 FORMAT_OPERATION:第一个 _ 之前的部分是格式(f16、f32、f64、f128),其余部分是运算(add、mulAdd、to_ui64、le_quiet、…)。名称在去除 -、_ 和空格后按不区分大小写的方式匹配。rounding 为 rnear_even、rnear_maxMag、rminMag、rmin、rmax 之一(也接受去掉开头 r 的形式,或 IEEE 名称 roundTiesToEven、roundTiesToAway、roundTowardZero、roundTowardNegative、roundTowardPositive)。tininess 为 "after"(默认)或 "before"(也接受 tininessAfter、tininessBefore)。exact(默认 false)选择 TestFloat 中 roundToInt 及整数转换的 -exact 变体。错误为 "unsupported TestFloat function name …"、"… format …"、"… operation …"、"… rounding mode …" 和 "… tininess mode …"。

///|
test "spec parse" {
  let spec = @testfloat_expr.TestFloatSpec::parse(
    "f128_mulAdd",
    "rminMag",
    tininess="before",
  ).unwrap()
  inspect(spec.operation() == @testfloat_expr.MulAdd, content="true")
  inspect(spec.format() == @bin_float.Binary128, content="true")
  inspect(spec.rounding() == @bin_float.RoundTowardZero, content="true")
  inspect(
    @testfloat_expr.TestFloatSpec::parse("f64_mul", "rodd") is Err(_),
    content="true",
  )
}

TestFloatSpec::function_name, format, operation, rounding, tininess, exact

这些访问器返回解析后的配置。

pub fn TestFloatSpec::function_name(Self) -> String
pub fn TestFloatSpec::format(Self) -> @bin_float.BinaryInterchangeFormat
pub fn TestFloatSpec::operation(Self) -> TestFloatOperation
pub fn TestFloatSpec::rounding(Self) -> @bin_float.BinaryRoundingMode
pub fn TestFloatSpec::tininess(Self) -> @bin_float.TininessDetection
pub fn TestFloatSpec::exact(Self) -> Bool

function_name 是按原样给出的名称。

解析

parse_testfloat

parse_testfloat(source, text, spec) 解析一个函数的向量。

pub fn parse_testfloat(String, String, TestFloatSpec) -> Result[TestFloatDocument, Array[ParseDiagnostic]]

各行会被修剪;空行和以 # 开头的行被跳过。一个向量有 k+2k + 2 个以空白分隔的字段,其中 kk 是该运算的操作数个数:kk 个操作数编码、期望结果,以及一个两位十六进制的标志掩码。操作数编码是 spec.format() 的十六进制位模式。对于算术运算,期望结果是一个编码;对于转换,是至多 16 位的十六进制整数;对于比较,是 0 或 1。字段数错误产生 "unexpected TestFloat field count",字段无法读取产生 "invalid TestFloat hexadecimal field"。只有当没有无效行时结果才为 Ok。

TestFloatDocument

TestFloatDocument 是一个已解析的向量文件。

pub struct TestFloatDocument {
  // private fields
}
pub fn TestFloatDocument::source(Self) -> String
pub fn TestFloatDocument::spec(Self) -> TestFloatSpec
pub fn TestFloatDocument::cases(Self) -> Array[TestFloatCase]
pub fn TestFloatDocument::case_count(Self) -> Int

cases 返回按文件顺序排列的向量的副本。

TestFloatCase

TestFloatCase 是一个向量。

pub struct TestFloatCase {
  // private fields
}
pub fn TestFloatCase::id(Self) -> String
pub fn TestFloatCase::line(Self) -> Int

id 为 FUNCTION:LINE,例如 f64_mulAdd:17。

ParseDiagnostic

ParseDiagnostic 是一个无效行。

pub struct ParseDiagnostic {
  // private fields
} derive(Eq, @debug.Debug)
pub fn ParseDiagnostic::source(Self) -> String
pub fn ParseDiagnostic::line(Self) -> Int
pub fn ParseDiagnostic::message(Self) -> String

执行

execute_document

execute_document(document, options?) 执行被选中的向量。

pub fn execute_document(TestFloatDocument, options? : RunOptions) -> RunSummary

对于分片数 nn 和索引 ii,当 k mod n=ik \bmod n = i 时执行第 kk 个向量(按文件顺序从 0 开始计数)。操作数被解码为 BinFloat,运算在 spec.format().context(rounding~, tininess~) 中执行。向量在以下情况下通过:

  • 算术运算:结果以相同的舍入和微小性规则重新编码到该格式后,其位模式与期望值完全一致,或者期望结果是任意 NaN 而实际结果是静默 NaN;并且运算标志与编码标志合并后的 SoftFloat 掩码等于期望掩码;
  • 整数转换:若期望掩码含有无效位 10,则转换必须报告无效(None),其值字段被忽略;否则转换必须返回期望的整数(有符号结果按二进制补码位模式比较);两种情况下标志掩码都必须相等;
  • 比较:布尔值与标志掩码都相等。

每个被选中的向量都是可执行的;不存在被跳过的向量。

RunOptions

RunOptions 选择一个分片。

pub struct RunOptions {
  // private fields
}
pub fn RunOptions::new(shard_count? : Int, shard_index? : Int) -> Self
pub fn RunOptions::shard_count(Self) -> Int
pub fn RunOptions::shard_index(Self) -> Int

默认值:一个分片,索引 0。除非 shard_count > 0 且 0 <= shard_index < shard_count,否则 RunOptions::new 中止。

结果

CaseResult

CaseResult 是一个向量的结果。

pub struct CaseResult {
  // private fields
}
pub fn CaseResult::id(Self) -> String
pub fn CaseResult::passed(Self) -> Bool
pub fn CaseResult::message(Self) -> String

消息:通过时为空;否则为 "value mismatch: expected HEX, actual HEX"、"integer mismatch: …"、"comparison mismatch: …" 或 "flags mismatch: expected M, actual M"(掩码以十进制表示)。

RunSummary

RunSummary 汇总一次运行。

pub struct RunSummary {
  // private fields
}
pub fn RunSummary::total_cases(Self) -> Int
pub fn RunSummary::selected_cases(Self) -> Int
pub fn RunSummary::passed_cases(Self) -> Int
pub fn RunSummary::failed_cases(Self) -> Int
pub fn RunSummary::results(Self) -> Array[CaseResult]
pub fn RunSummary::success(Self) -> Bool

total_cases 是文档中的向量数,selected_cases = passed_cases + failed_cases 是本分片执行的向量数,当没有向量失败时 success 为真。

trait 实现

TestFloatOperation、TestFloatSpec 和 ParseDiagnostic 的相等性与 Debug

这些方法比较所有字段,并为 Debug 渲染值。新代码中请使用 ==、!= 和 debug_inspect。

pub fn TestFloatOperation::equal(Self, Self) -> Bool
pub fn TestFloatOperation::not_equal(Self, Self) -> Bool
pub fn TestFloatOperation::to_repr(Self) -> @debug.Repr
pub fn TestFloatSpec::equal(Self, Self) -> Bool
pub fn TestFloatSpec::not_equal(Self, Self) -> Bool
pub fn TestFloatSpec::to_repr(Self) -> @debug.Repr
pub fn ParseDiagnostic::equal(Self, Self) -> Bool
pub fn ParseDiagnostic::not_equal(Self, Self) -> Bool
pub fn ParseDiagnostic::to_repr(Self) -> @debug.Repr

完整公共接口

此快照是该包生成的 pkg.generated.mbti。当正文与接口不一致时,以接口为准。

// Generated using `moon info`, DON'T EDIT IT
package "Luna-Flow/floating/frontend/testfloat_expr"

import {
  "Luna-Flow/floating/bin_float",
  "moonbitlang/core/debug",
}

// Values
pub fn execute_document(TestFloatDocument, options? : RunOptions) -> RunSummary

pub fn parse_testfloat(String, String, TestFloatSpec) -> Result[TestFloatDocument, Array[ParseDiagnostic]]

// Errors

// Types and methods
pub struct CaseResult {
  // private fields
}
pub fn CaseResult::id(Self) -> String
pub fn CaseResult::message(Self) -> String
pub fn CaseResult::passed(Self) -> Bool

pub struct ParseDiagnostic {
  // private fields
} derive(Eq, @debug.Debug)
pub fn ParseDiagnostic::equal(Self, Self) -> Bool
pub fn ParseDiagnostic::line(Self) -> Int
pub fn ParseDiagnostic::message(Self) -> String
pub fn ParseDiagnostic::not_equal(Self, Self) -> Bool
pub fn ParseDiagnostic::source(Self) -> String
pub fn ParseDiagnostic::to_repr(Self) -> @debug.Repr

pub struct RunOptions {
  // private fields
}
pub fn RunOptions::new(shard_count? : Int, shard_index? : Int) -> Self
pub fn RunOptions::shard_count(Self) -> Int
pub fn RunOptions::shard_index(Self) -> Int

pub struct RunSummary {
  // private fields
}
pub fn RunSummary::failed_cases(Self) -> Int
pub fn RunSummary::passed_cases(Self) -> Int
pub fn RunSummary::results(Self) -> Array[CaseResult]
pub fn RunSummary::selected_cases(Self) -> Int
pub fn RunSummary::success(Self) -> Bool
pub fn RunSummary::total_cases(Self) -> Int

pub struct TestFloatCase {
  // private fields
}
pub fn TestFloatCase::id(Self) -> String
pub fn TestFloatCase::line(Self) -> Int

pub struct TestFloatDocument {
  // private fields
}
pub fn TestFloatDocument::case_count(Self) -> Int
pub fn TestFloatDocument::cases(Self) -> Array[TestFloatCase]
pub fn TestFloatDocument::source(Self) -> String
pub fn TestFloatDocument::spec(Self) -> TestFloatSpec

pub(all) enum TestFloatOperation {
  Add
  Subtract
  Multiply
  Divide
  SquareRoot
  MulAdd
  Remainder
  RoundToInt
  ToInt32
  ToInt64
  ToUInt32
  ToUInt64
  Equal
  LessEqual
  Less
  EqualSignaling
  LessEqualQuiet
  LessQuiet
} derive(Eq, @debug.Debug)
pub fn TestFloatOperation::equal(Self, Self) -> Bool
pub fn TestFloatOperation::not_equal(Self, Self) -> Bool
pub fn TestFloatOperation::to_repr(Self) -> @debug.Repr

pub struct TestFloatSpec {
  // private fields
} derive(Eq, @debug.Debug)
pub fn TestFloatSpec::equal(Self, Self) -> Bool
pub fn TestFloatSpec::exact(Self) -> Bool
pub fn TestFloatSpec::format(Self) -> @bin_float.BinaryInterchangeFormat
pub fn TestFloatSpec::function_name(Self) -> String
pub fn TestFloatSpec::not_equal(Self, Self) -> Bool
pub fn TestFloatSpec::operation(Self) -> TestFloatOperation
pub fn TestFloatSpec::parse(String, String, tininess? : String, exact? : Bool) -> Result[Self, String]
pub fn TestFloatSpec::rounding(Self) -> @bin_float.BinaryRoundingMode
pub fn TestFloatSpec::tininess(Self) -> @bin_float.TininessDetection
pub fn TestFloatSpec::to_repr(Self) -> @debug.Repr

// Type aliases

// Traits