def API
def 是 floating 各包的共享词汇。它定义了符号分类 Sign、四路比较结果 PartialOrder、本仓库中每种标量或区间表示都实现的开放 trait Floating、基于该 trait 构建的四个泛型谓词,并重新导出 Luna-Flow/arithmetic 中的上下文、舍入、分类和错误类型,使调用者只需一次导入。它不包含任何算术运算。教程 展示了这些词汇的用法;设计页面 陈述了 trait 定律,并解释了为何 PartialOrder 不是全序。
本页的每个示例都是一个能在当前分支上编译通过的完整测试。该包以 @def 导入;@lf_arith 即 Luna-Flow/arithmetic。
符号与比较结果
Sign
Sign 是 Floating::sign 返回的三路符号分类。
pub(all) enum Sign {
Negative
Zero
Positive
} derive(Eq)
两种带符号零都返回 Zero,因此 Sign 不区分 与 ;当零的符号位很重要时,请使用具体的包(例如 BinFloat::is_negative_zero)。具体实现对 NaN 也返回 Zero,而区间在包含 时返回 Zero(参见 Floating::sign)。Sign 也是 semantic 包中 SemanticScalar::Infinity 的载荷,以及 BinFloat::inf 等构造函数的参数。
///|
test "Sign values" {
let s = @def.Floating::sign(@bin_float.BinFloat::from_int(-3))
inspect(s == @def.Sign::Negative, content="true")
let z = @def.Floating::sign(@bin_float.BinFloat::from_double(-0.0))
inspect(z == @def.Sign::Zero, content="true")
}
PartialOrder
PartialOrder 是 IEEE 754 比较的结果:两个浮点数据之间恰好成立 小于、等于、大于 和 无序 这四种互斥关系之一。
pub(all) enum PartialOrder {
Less
Equal
Greater
Unordered
} derive(Eq)
当且仅当至少一个操作数为 NaN 时 Unordered 成立; 和 比较 Equal。该类型由 bin_float 中的 BinFloat::compare_quiet 和 BinFloat::compare_signaling 返回(各自附带该比较的标志)。它仅是一个值类型;def 本身不执行任何比较。为何是四种结果而非 Compare 实例,其推导见设计页面。
///|
test "PartialOrder from an IEEE comparison" {
let one = @bin_float.BinFloat::from_int(1)
let nan = @bin_float.BinFloat::nan()
let (relation, flags) = one.compare_quiet(nan)
inspect(relation == @def.PartialOrder::Unordered, content="true")
inspect(flags.invalid_operation(), content="false")
let (signaling, signaling_flags) = one.compare_signaling(nan)
inspect(signaling == @def.PartialOrder::Unordered, content="true")
inspect(signaling_flags.invalid_operation(), content="true")
let zeros = @bin_float.BinFloat::from_double(-0.0).compare_quiet(
@bin_float.BinFloat::zero(),
)
inspect(zeros.0 == @def.PartialOrder::Equal, content="true")
}
Floating trait
Floating 是本仓库中所有表示共享的观察与重设精度接口。
pub(open) trait Floating {
fn classify(Self) -> @arithmetic.FpClass
fn sign(Self) -> Sign
fn precision(Self) -> Int
fn with_precision(Self, Int, @arithmetic.RoundingMode) -> Self
fn normalized(Self) -> Self
}
该 trait 为 pub(open),因此下游类型可以实现它。在本仓库中,@bin_float.BinFloat、@decimal.Decimal、@decimal_gda.Decimal 和 @ball_float.BallFloat 实现了它。自 MoonBit 0.10 迁移以来,trait 方法不再自动提升,因此泛型代码以限定形式 @def.Floating::classify(x) 调用它们;具体类型也提供同名的固有方法(x.classify())。每个实现应满足的定律列于设计页面。
Floating::classify
classify 返回值的类别:Finite、Infinity 或 NaN。
fn classify(Self) -> @arithmetic.FpClass
对于标量类型,这是将信号 NaN 与静默 NaN 合并后的 IEEE 类别。对于 BallFloat,有界非空区间为 Finite,带有无穷端点的区间(包括整条实数线)为 Infinity,空区间为 NaN。全函数;从不中止。
Floating::sign
sign 返回值的符号分类。
fn sign(Self) -> Sign
| 实现 | Negative | Zero | Positive |
|---|---|---|---|
BinFloat,两种 Decimal | 值 ,包括 | 及所有 NaN | 值 ,包括 |
BallFloat |
BallFloat::sign 在空区间上会中止,因为空区间没有符号;请先检测 @def.is_nan(x)(当且仅当为空区间时为真)。
Floating::precision
precision 返回值上存储的工作精度:对 BinFloat 和 BallFloat 端点为有效二进制位数,对两种 Decimal 类型为有效十进制位数。结果总是至少为 。
Floating::with_precision
with_precision(x, p, mode) 返回以精度 重新表示的 x。
fn with_precision(Self, Int, @arithmetic.RoundingMode) -> Self
对于有限标量,值按给定方向舍入到其基数下的 位有效数字,指数范围不受限制,因此从不上溢或下溢;不报告任何标志(如需标志,请使用具体包的 *_ctx API)。无穷与 NaN 保持其类别,仅改变所存储的精度。对于 BallFloat,结果是输入的包络:中心按 mode 舍入,舍入误差加到半径上,因此无论 mode 为何,x 的每个成员都仍是结果的成员。
Floating::normalized
normalized 返回值的规范代表,不改变其数学值。
fn normalized(Self) -> Self
对于 BinFloat,这是系数为奇数(或为零)的表示;对于两种 Decimal 类型,它去除系数末尾的零,因此 1.500 变为 1.5(同值类改变,值不变)。非有限值原样返回。normalized 是幂等的。
///|
fn[F : @def.Floating] describe(x : F) -> String {
let class = match @def.Floating::classify(x) {
Finite => "finite"
Infinity => "infinite"
NaN => "nan"
}
let sign = match @def.Floating::sign(x) {
Negative => "-"
Zero => "0"
Positive => "+"
}
"\{class} \{sign} precision=\{@def.Floating::precision(x)}"
}
///|
test "Floating observations" {
inspect(
describe(@bin_float.BinFloat::from_double(-0.0)),
content="finite 0 precision=53",
)
inspect(
describe(@decimal.Decimal::from_string("-1.50").unwrap()),
content="finite - precision=34",
)
inspect(
describe(@decimal_gda.Decimal::from_string("-Inf").unwrap()),
content="infinite - precision=34",
)
let around_zero = @ball_float.BallFloat::from_bounds(
@bin_float.BinFloat::from_int(-1),
@bin_float.BinFloat::from_int(1),
)
inspect(describe(around_zero), content="finite 0 precision=53")
}
///|
test "Floating re-precision and normalization" {
let d = @decimal.Decimal::from_string("2.71828").unwrap()
let cut = @def.Floating::with_precision(d, 3, @lf_arith.RoundingMode::TowardZero)
inspect(cut.to_string(), content="2.71")
let ten = @def.Floating::with_precision(
@bin_float.BinFloat::from_int(10),
2,
@lf_arith.RoundingMode::ToNearestEven,
)
inspect(ten.to_string(), content="1p3")
inspect(ten.precision(), content="2")
let cohort = @decimal.Decimal::from_string("1.500").unwrap()
inspect(@def.Floating::normalized(cohort).to_string(), content="1.5")
}
泛型谓词
is_finite, is_infinite, is_nan, is_zero
这些函数检测任意 Floating 值的类别。
pub fn[F : Floating] is_finite(F) -> Bool
pub fn[F : Floating] is_infinite(F) -> Bool
pub fn[F : Floating] is_nan(F) -> Bool
pub fn[F : Floating] is_zero(F) -> Bool
对每个值,前三者中恰有一个为真。对于标量,is_zero 对两种带符号零都为真。对于 BallFloat,is_zero 对每个包含零的有界区间(例如 )都为真,而不仅限于 ;若你指的是其他含义,请使用 BallFloat::contains_zero 或比较区间端点。is_zero 从不在空区间上调用 sign,因为合取在 classify 处即短路停止。
///|
test "generic predicates" {
inspect(@def.is_zero(@bin_float.BinFloat::from_double(-0.0)), content="true")
inspect(
@def.is_finite(@decimal.Decimal::from_string("NaN").unwrap()),
content="false",
)
inspect(@def.is_nan(@ball_float.BallFloat::empty()), content="true")
let around_zero = @ball_float.BallFloat::from_bounds(
@bin_float.BinFloat::from_int(-1),
@bin_float.BinFloat::from_int(1),
)
inspect(@def.is_zero(around_zero), content="true")
}
重新导出的类型
def 以 pub using 重新导出这些类型,因此 @def.RoundingMode 与 @lf_arith.RoundingMode 指同一类型。它们的定义和语义由 Luna-Flow/arithmetic 文档说明。
pub using @arithmetic {type ArithmeticContext}
pub using @arithmetic {type ArithmeticError}
pub using @arithmetic {type ArithmeticErrorKind}
pub using @bigint {type BigInt}
pub using @arithmetic {type CertificationFailureDetail}
pub using @arithmetic {type CertificationFailureReason}
pub using @arithmetic {type CertificationStage}
pub using @arithmetic {type FpClass}
pub using @arithmetic {type RoundingMode}
| 别名 | 在 floating 中的作用 |
|---|---|
ArithmeticContext | 传递给 arithmetic 上下文 trait 的精度、舍入及可选指数界限;由各自的 from_arithmetic_context 构造函数映射为 BinaryContext / DecimalContext。 |
ArithmeticError, ArithmeticErrorKind | 所有返回 Result 的 API(*_checked、try_*)以及各 checked 包装包的结构化错误。 |
CertificationFailureDetail, CertificationFailureReason, CertificationStage | 种类为 CertificationFailure 的 ArithmeticError 的载荷:表示某个初等函数的正确舍入结果未能在其预算内完成认证。 |
FpClass | Floating::classify 的结果。 |
RoundingMode | with_precision 及各具体构造函数接受的五种舍入方向。 |
BigInt | moonbitlang/core/bigint 的任意精度整数,用于表示系数。 |
///|
test "aliases name the arithmetic types" {
let ctx : @def.ArithmeticContext = @lf_arith.ArithmeticContext::new(10)
inspect(ctx.precision, content="10")
let mode : @def.RoundingMode = ToNearestEven
inspect(mode == @lf_arith.RoundingMode::ToNearestEven, content="true")
}
trait 实现
Sign::equal, Sign::not_equal, PartialOrder::equal, PartialOrder::not_equal
这些方法是派生的 Eq 实例,经显式提升以使 a.equal(b) 仍然可用;请优先使用 == 和 !=。
pub fn Sign::equal(Self, Self) -> Bool
pub fn Sign::not_equal(Self, Self) -> Bool
pub fn PartialOrder::equal(Self, Self) -> Bool
pub fn PartialOrder::not_equal(Self, Self) -> Bool
完整公共接口
以下快照是该包完整的生成接口。
// Generated using `moon info`, DON'T EDIT IT
package "Luna-Flow/floating/def"
import {
"Luna-Flow/arithmetic",
"moonbitlang/core/bigint",
}
// Values
pub fn[F : Floating] is_finite(F) -> Bool
pub fn[F : Floating] is_infinite(F) -> Bool
pub fn[F : Floating] is_nan(F) -> Bool
pub fn[F : Floating] is_zero(F) -> Bool
// Errors
// Types and methods
pub(all) enum PartialOrder {
Less
Equal
Greater
Unordered
} derive(Eq)
pub fn PartialOrder::equal(Self, Self) -> Bool
pub fn PartialOrder::not_equal(Self, Self) -> Bool
pub(all) enum Sign {
Negative
Zero
Positive
} derive(Eq)
pub fn Sign::equal(Self, Self) -> Bool
pub fn Sign::not_equal(Self, Self) -> Bool
// Type aliases
pub using @arithmetic {type ArithmeticContext}
pub using @arithmetic {type ArithmeticError}
pub using @arithmetic {type ArithmeticErrorKind}
pub using @bigint {type BigInt}
pub using @arithmetic {type CertificationFailureDetail}
pub using @arithmetic {type CertificationFailureReason}
pub using @arithmetic {type CertificationStage}
pub using @arithmetic {type FpClass}
pub using @arithmetic {type RoundingMode}
// Traits
pub(open) trait Floating {
fn classify(Self) -> @arithmetic.FpClass
fn sign(Self) -> Sign
fn precision(Self) -> Int
fn with_precision(Self, Int, @arithmetic.RoundingMode) -> Self
fn normalized(Self) -> Self
}