itl_expr 教程
本教程介绍如何针对 ball_float 运行以 ITF1788 套件 ITL 格式编写的 IEEE 1788 区间测试用例。你将把 ITL 文本解析为用例,逐个执行,并汇总结果。处理整个文件的命令行运行器是 itl_expr_cli。
快速入门
将该包添加到 moon.pkg:
import {
"Luna-Flow/floating/frontend/itl_expr",
}
解析一个测试用例块并运行:
///|
test "quick start" {
let source =
#|testcase demo {
#| add [1.0,2.0] [3.0,4.0] = [4.0,6.0];
#| intersection [1.0,3.0] [2.0,4.0] = [2.0,3.0];
#|}
let cases = @itl_expr.parse_itl(source).unwrap()
let summary = @itl_expr.summarize_results(
cases.map(case => @itl_expr.execute_case(case)),
)
inspect(summary.passed_cases(), content="2")
inspect(summary.success(), content="true")
}
每条语句 operation operand… = expected; 成为一个 ItlCase,其 id 为 testcase:index。
日常任务
检查解析后的用例
///|
test "parsed cases" {
let source =
#|testcase bounds {
#| inf [-0x1.8p1,2.5] = -3.0;
#| mul [1.0,2.0]
#| [entire] = [entire];
#|}
let cases = @itl_expr.parse_itl(source).unwrap()
inspect(cases.map(c => c.id()).join(" "), content="bounds:1 bounds:2")
inspect(cases[1].operation(), content="mul")
inspect(cases[1].operands().join(" "), content="[1.0,2.0] [entire]")
inspect(cases[1].expected(), content="[entire]")
}
一条语句可以跨越多行,以 ; 结束。端点可以是十进制或十六进制(0x1.8p1)文本,并且可以识别字面量 [empty]、[entire] 和 [nai]。
检查装饰
预期值上的装饰(decoration)后缀(_com、_dac、_def、_trv、_ill)使装饰成为测试的一部分。没有后缀时只比较集合。失败消息以中点-半径形式打印区间:
///|
test "decorations" {
let source =
#|testcase deco {
#| add [1.0,2.0]_com [3.0,4.0]_com = [4.0,6.0]_com;
#| add [1.0,2.0]_com [3.0,4.0]_com = [4.0,6.0]_def;
#| add [1.0,2.0]_com [3.0,4.0]_com = [4.0,6.0];
#|}
let cases = @itl_expr.parse_itl(source).unwrap()
let passed = cases.map(c => @itl_expr.execute_case(c).passed().to_string())
inspect(passed.join(" "), content="true false true")
inspect(
@itl_expr.execute_case(cases[1]).message(),
content="expected 5p0 +/- 1p0_def, got 5p0 +/- 1p0_com",
)
}
数值、布尔值与重叠状态
除区间结果外,ITL 用例还可以预期一个数值(inf、sup、mid、rad、wid、mag、mig)、一个布尔值(isEmpty、subset、isMember、…)或一个重叠状态名:
///|
test "other result kinds" {
let source =
#|testcase kinds {
#| wid [1.0,3.5] = 2.5;
#| subset [1.0,2.0] [0.0,3.0] = true;
#| isMember 4.0 [1.0,3.0] = false;
#| overlap [1.0,2.0] [2.0,3.0] = meets;
#|}
let cases = @itl_expr.parse_itl(source).unwrap()
let summary = @itl_expr.summarize_results(
cases.map(c => @itl_expr.execute_case(c)),
)
inspect(summary.passed_cases(), content="4")
}
不支持的用例与格式错误的用例
执行器未实现的用例为 Unsupported;操作数无法读取的用例为 Diagnostic。两者都不计为失败,但诊断用例会使 success() 为 false:
///|
test "dispositions" {
let source =
#|testcase odd {
#| mulRevToPair [1.0,2.0] [3.0,4.0] = [1.0,2.0];
#| sqrt [one,two] = [1.0,2.0];
#|}
let results = @itl_expr.parse_itl(source)
.unwrap()
.map(c => @itl_expr.execute_case(c))
let summary = @itl_expr.summarize_results(results)
inspect(summary.unsupported_cases(), content="1")
inspect(summary.diagnostic_cases(), content="1")
inspect(summary.success(), content="false")
}
深入了解
- 语料运行。
just conformance run interval获取固定版本的 ITF1788 语料,构建 native 运行器,并运行testdata/interval/interpreter_stages.json中列出的严格阶段;参见验证。 - 按运算过滤。 CLI 的
--operation NAME选项只保留该运算的用例;在代码中,可在执行前按operation()过滤cases。 - 精度。
execute_case(case, precision=p)以p位解析端点;区间运算本身舍入到 binary64,因此对 ITF1788 数据请保持默认值53。
常见陷阱
- 十进制端点按就近舍入。 诸如
0.1的端点被读作最接近的 binary64 数,而不是向外舍入,因此[0.1,0.1]是由该 binary64 数构成的单点区间。 - 不检查信号。 预期值之后的
signal …等 ITL 注解会使预期值无法读取;这类用例会成为不支持或诊断用例,而不会通过。 - 解析错误会使输入被拒绝。 只要有任何语句缺少
=或运算,或者文本在语句中途结束,parse_itl就只返回诊断。
后续步骤
- itl_expr API:每个条目以及已执行运算的列表。
- itl_expr 设计:通过规则。
- ball_float 教程:被测试的区间算术。