arithmetic API

Luna-Flow/linear-algebra/arithmetic 是本仓库的标量运算层。它重新导出线性代数代码从 Luna-Flow/luna-generic 和 Luna-Flow/arithmetic 中使用的标量类型和 trait,并新增五个小型运算 trait:Abs、ApproxEq、CheckedDiv、CheckedSqrt 和 CheckedCompare。运算 trait 只表明某个运算可用,并不声明代数定律。

源码:src/arithmetic/operation_traits.mbt、src/arithmetic/alias.mbt。设计考量见 arithmetic 设计。

导入

本页示例使用以下别名:

///|
import {
  "Luna-Flow/linear-algebra/arithmetic" @la_arithmetic,
  "Luna-Flow/arithmetic" @lf_arith,
}

重导出的名称

该包通过 pub using 重新导出这些上游名称,因此 @la_arithmetic.Sqrt 和 @lf_arith.Sqrt 指代同一个 trait。它们的行为由上游文档说明:luna-generic 和 arithmetic。

名称种类来源含义
Zerotraitluna-generic加法单位元 zero()
Onetraitluna-generic乘法单位元 one()
Inversetraitluna-generic乘法逆元 inv(x)
Conjugatetraitluna-generic对合 conjugate(x);内置实数类型没有实例
Sqrttraitarithmetic非受检 sqrt(x)
Cbrttraitarithmetic非受检 cbrt(x)
Powertraitarithmetic非受检 pow(x, y)
Exponentialtraitarithmeticexp(x), exp2(x)
Logarithmictraitarithmeticln(x), log2(x), log10(x)
Constantstraitarithmeticpi(), tau(), e()
SqrtCheckedtraitarithmetic返回 Result 的 sqrt_checked(x, ctx)
DivCheckedtraitarithmetic返回 Result 的 div_checked(x, y, ctx)
CompareCheckedtraitarithmetic返回 Result[Int, _] 的 compare_checked(x, y)
ArithmeticContext类型arithmetic传递给受检运算的精度与舍入设置
ArithmeticError类型arithmetic带有 kind 和 message 的结构化标量错误
ArithmeticErrorKind类型arithmeticDivisionByZero, DomainError, UnorderedComparison, …
FpClass类型arithmeticFinite, Infinity, NaN
RoundingMode类型arithmeticToNearestEven, TowardZero, …

绝对值

Abs

Abs 标记具有绝对值的标量类型。

pub(open) trait Abs {
  fn abs(Self) -> Self
}
pub impl Abs for Int
pub impl Abs for Float
pub impl Abs for Double

Abs::abs

Abs::abs 返回 ∣x∣|x|。

fn Abs::abs(Self) -> Self

这些实现委托给 luna-generic 的 Num::abs。对于 Int,∣−231∣|-2^{31}| 会按补码算术回绕为 −231-2^{31}。

///|
fn[T : @la_arithmetic.Abs] arith_api_magnitude(x : T) -> T {
  @la_arithmetic.Abs::abs(x)
}

///|
test "Abs on integers and doubles" {
  inspect(arith_api_magnitude(-3), content="3")
  inspect(arith_api_magnitude(-2.5), content="2.5")
}

近似相等

ApproxEq

ApproxEq 标记支持近似比较的标量类型。

pub(open) trait ApproxEq {
  fn approx_eq(Self, Self) -> Bool
}
pub impl ApproxEq for Int
pub impl ApproxEq for Float
pub impl ApproxEq for Double

ApproxEq::approx_eq

ApproxEq::approx_eq 判断两个值之差是否在固定的绝对容差之内。

fn ApproxEq::approx_eq(Self, Self) -> Bool
类型规则
Inta=ba = b
Float∣a−b∣≤10−6\lvert a - b\rvert \le 10^{-6}
Double∣a−b∣≤10−12\lvert a - b\rvert \le 10^{-12}

该容差是绝对的,因此对大数值过严、对极小数值过松,而且该关系不具有传递性。只要有操作数是 NaN,它就返回 false。其后果见设计页面。

///|
test "ApproxEq uses an absolute tolerance" {
  inspect(
    @la_arithmetic.ApproxEq::approx_eq(1.0, 1.0 + 1.0e-13),
    content="true",
  )
  inspect(
    @la_arithmetic.ApproxEq::approx_eq(1.0e20, 1.0e20 + 1.0e5),
    content="false",
  )
  inspect(@la_arithmetic.ApproxEq::approx_eq(3, 3), content="true")
}

受检运算

受检 trait 返回 Result[_, ArithmeticError],而不是 NaN 或无穷大。Float 和 Double 的实现委托给上游的 DivChecked、SqrtChecked 和 CompareChecked trait;为了接口统一,它们接受一个 ArithmeticContext,但会忽略它,因为硬件二进制浮点数的精度是固定的。

CheckedDiv

CheckedDiv 标记具有能报告非法操作数的除法的标量类型。

pub(open) trait CheckedDiv {
  fn checked_div(Self, Self, @Luna-Flow/arithmetic.ArithmeticContext) -> Result[Self, @Luna-Flow/arithmetic.ArithmeticError]
}
pub impl CheckedDiv for Float
pub impl CheckedDiv for Double

CheckedDiv::checked_div

CheckedDiv::checked_div(x, y, ctx) 返回 Ok(x / y) 或一个错误。

fn CheckedDiv::checked_div(Self, Self, ArithmeticContext) -> Result[Self, ArithmeticError]
操作数结果
0/00 / 0Err,kind 为 DomainError
±∞/±∞\pm\infty / \pm\inftyErr,kind 为 DomainError
x/0x / 0, x≠0x \ne 0Err,kind 为 DivisionByZero
其他情况Ok(x / y),舍入到最近值

CheckedSqrt

CheckedSqrt 标记具有能报告定义域错误的平方根的标量类型。

pub(open) trait CheckedSqrt {
  fn checked_sqrt(Self, @Luna-Flow/arithmetic.ArithmeticContext) -> Result[Self, @Luna-Flow/arithmetic.ArithmeticError]
}
pub impl CheckedSqrt for Float
pub impl CheckedSqrt for Double

CheckedSqrt::checked_sqrt

CheckedSqrt::checked_sqrt(x, ctx) 在 x≥0x \ge 0 时返回 Ok(√x),在 x<0x < 0 时返回 kind 为 DomainError 的错误。

fn CheckedSqrt::checked_sqrt(Self, ArithmeticContext) -> Result[Self, ArithmeticError]

NaN 参数会原样传递为 Ok(NaN)。

CheckedCompare

CheckedCompare 标记具有能报告无序操作数的三路比较的标量类型。

pub(open) trait CheckedCompare {
  fn checked_compare(Self, Self) -> Result[Int, @Luna-Flow/arithmetic.ArithmeticError]
}
pub impl CheckedCompare for Float
pub impl CheckedCompare for Double

CheckedCompare::checked_compare

CheckedCompare::checked_compare(x, y) 在 x<yx < y、x=yx = y 和 x>yx > y 时分别返回 Ok(-1)、Ok(0) 或 Ok(1),当任一操作数为 NaN 时返回 kind 为 UnorderedComparison 的错误。

fn CheckedCompare::checked_compare(Self, Self) -> Result[Int, ArithmeticError]

三个受检 trait 的综合示例:

///|
test "checked scalar operations" {
  let ctx = @lf_arith.ArithmeticContext::new(53)
  inspect(
    @la_arithmetic.CheckedDiv::checked_div(6.0, 2.0, ctx).unwrap(),
    content="3",
  )
  match @la_arithmetic.CheckedDiv::checked_div(1.0, 0.0, ctx) {
    Err(e) => inspect(e.is_division_by_zero(), content="true")
    Ok(_) => fail("1 / 0 must fail")
  }
  match @la_arithmetic.CheckedSqrt::checked_sqrt(-4.0, ctx) {
    Err(e) => inspect(e.is_domain_error(), content="true")
    Ok(_) => fail("sqrt(-4) must fail")
  }
  inspect(
    @la_arithmetic.CheckedCompare::checked_compare(2.0, 3.0).unwrap(),
    content="-1",
  )
  let nan = 0.0 / 0.0
  inspect(
    @la_arithmetic.CheckedCompare::checked_compare(nan, 1.0) is Err(_),
    content="true",
  )
}

这些 trait 的使用位置

具体的矩阵包从 luna-generic(Zero、AddMonoid、Semiring、Field、Num)以及 Sqrt 获取标量约束。@mutable 的数值例程通过此处的重导出使用 Sqrt,并使用它们自己的 Tolerance trait(见 mutable API)。本地 trait Abs、ApproxEq 以及各受检 trait 是供下游算法使用的构件;本仓库中没有任何矩阵方法依赖它们。