internal API

internal 包含各数值核心共享的精确整数与有理数辅助函数:2、5 和 10 的幂,数字位数计数,去除尾部因子,带显式舍入模式的整数除法,十进制字符串拆分器,最简有理数,二进有理数包络,以及经认证初等函数的细化预算。bin_float、decimal、decimal_gda、ball_float、semantic 以及 consistency 测试都使用它。它是一个内部包:无法从 Luna-Flow/floating 之外导入,其接口可能会变化。因此示例不会被编译。设计页面证明舍入与包络不变式;教程展示各核心如何使用这些辅助函数。

导入(仅限模块内部):

import {
  "Luna-Flow/floating/internal",
}

@bigint.BigInt 即 moonbitlang/core/bigint;接口将 Luna-Flow/arithmetic 显示为 @arithmetic(RoundingMode、ArithmeticError、CertificationStage、CertificationFailureReason),并使用 @def.Sign。

整数基础

bigint_zero, bigint_one

这些函数返回 BigInt 常量 00 和 11。

pub fn bigint_zero() -> @bigint.BigInt
pub fn bigint_one() -> @bigint.BigInt

abs_bigint, sign_of_bigint, compare_abs

abs_bigint(x) 为 ∣x∣|x|,sign_of_bigint(x) 为 Negative、Zero 或 Positive,compare_abs(a, b) 比较 ∣a∣|a| 与 ∣b∣|b|(返回负数、零或正数的 Int)。

pub fn abs_bigint(@bigint.BigInt) -> @bigint.BigInt
pub fn sign_of_bigint(@bigint.BigInt) -> @def.Sign
pub fn compare_abs(@bigint.BigInt, @bigint.BigInt) -> Int

幂

pow2, pow5, pow10

这些函数返回 2n2^n、5n5^n 和 10n10^n。

pub fn pow2(Int) -> @bigint.BigInt
pub fn pow5(Int) -> @bigint.BigInt
pub fn pow10(Int) -> @bigint.BigInt

当 n<0n < 0 时它们会中止。pow2 是一次移位。pow5 和 pow10 读取一个进程级缓存,该缓存初始包含 n≤18n \le 18 的幂,并按需扩展到至多 n=4096n = 4096;更大的幂每次都重新计算,不做缓存。

digits10

digits10(x) 是 ∣x∣|x| 的十进制位数,且 digits10(0) == 1。

pub fn digits10(@bigint.BigInt) -> Int

对于 x≠0x \ne 0,它返回满足 10d−1≤∣x∣<10d10^{d-1} \le |x| < 10^{d} 的唯一 dd:先根据位长给出估计,再通过与 10 的幂比较加以修正(不构造十进制字符串)。

尾部因子

remove_factor2

remove_factor2(sig, exp) 从 sig 中去除所有因子 2,并相应调整二进制指数。

pub fn remove_factor2(@bigint.BigInt, Int) -> (@bigint.BigInt, Int)

对于 sig≠0\mathit{sig} \ne 0,它返回 (sig/2t,exp+t)(\mathit{sig}/2^t, \mathit{exp} + t),其中 tt 是 ∣sig∣|\mathit{sig}| 尾部零比特的个数,因此 sig⋅2exp\mathit{sig} \cdot 2^{\mathit{exp}} 保持不变,且新的有效数为奇数。对于 sig=0\mathit{sig} = 0,它返回 (0,0)(0, 0)。

remove_factor10

remove_factor10(coeff, exp) 从 coeff 中去除所有因子 10,并相应调整十进制指数。

pub fn remove_factor10(@bigint.BigInt, Int) -> (@bigint.BigInt, Int)

值 coeff⋅10exp\mathit{coeff} \cdot 10^{\mathit{exp}} 保持不变,且新的系数不能被 10 整除。零得到 (0,0)(0, 0)。

trim_trailing_decimal_zeros

trim_trailing_decimal_zeros(coeff, exp, max_drop?) 去除至多 max_drop 个十进制尾随零。

pub fn trim_trailing_decimal_zeros(@bigint.BigInt, Int, max_drop? : Int) -> (@bigint.BigInt, Int, Int)

它返回 (c′,e′,k)(c', e', k),满足 c=c′⋅10kc = c' \cdot 10^{k}、e′=e+ke' = e + k,且 kk 在 k≤k \le max_drop 的约束下取最大。负的 max_drop(默认 −1-1)表示没有限制。零得到 (0,0,0)(0, 0, 0)。设置限制可让调用方在某个目标指数处停下,正如 decNumber 风格的、截尾到理想指数的做法那样。

exact_divide_by_power_of_ten

当除法精确时,exact_divide_by_power_of_ten(coeff, shift) 为 Some(coeff / 10^shift),否则为 None。

pub fn exact_divide_by_power_of_ten(@bigint.BigInt, Int) -> @bigint.BigInt?

符号保持不变。对于任意 shift,零都得到 Some(0);对于非零系数,负的 shift 会导致中止。

整数商的舍入

round_positive_div

round_positive_div(n, d, negative, mode) 将商 n/dn/d 舍入为一个整数量值。

pub fn round_positive_div(@bigint.BigInt, @bigint.BigInt, Bool, @arithmetic.RoundingMode) -> @bigint.BigInt

要求 n≥0n \ge 0 且 d>0d > 0(否则中止)。negative 是量值为 n/dn/d 的实数商的符号;结果为 ∣∘mode((−1)negative n/d)∣|\circ_{\text{mode}}((-1)^{\text{negative}}\, n/d)|,其中 ∘\circ 表示舍入到整数:

mode对 n=qd+rn = qd + r、0≤r<d0 \le r < d 的结果
TowardZeroqq
TowardPositiveq+[r>0∧¬negative]q + [r > 0 \wedge \neg\text{negative}]
TowardNegativeq+[r>0∧negative]q + [r > 0 \wedge \text{negative}]
AwayFromZeroq+[r>0]q + [r > 0]
ToNearestEvenq+[2r>d∨(2r=d∧q odd)]q + [2r > d \vee (2r = d \wedge q \text{ odd})]

结果是精确的(等于 n/dn/d)当且仅当 r=0r = 0。

round_shift

round_shift(m, s, negative, mode) 即用移位计算的 round_positive_div(m, 2^s, negative, mode)。

pub fn round_shift(@bigint.BigInt, Int, Bool, @arithmetic.RoundingMode) -> @bigint.BigInt

mm 应为非负(不做检查)。当 s≤0s \le 0 时,它原样返回 mm。

十进制字符串

split_decimal_string

split_decimal_string(text) 将一个有限十进制字面量拆分为符号、数字串和指数。

pub fn split_decimal_string(String) -> (Bool, String, Int)?

所接受的语法为

[+|-] digit* [. digit*] [(e|E) [+|-] digit+]     with at least one mantissa digit

结果 (neg,D,q)(\mathit{neg}, D, q) 满足 value=(−1)neg⋅D⋅10q\text{value} = (-1)^{\mathit{neg}} \cdot D \cdot 10^{q},其中 DD 是全部尾数数字组成的字符串(保留前导零),qq 是书写的指数减去小数部分的位数。书写的指数在相减之前饱和于 ±1 500 000 000\pm 1\,500\,000\,000,因此巨大的指数不会使 Int 溢出。其他任何输入,包括 inf 和 nan,都得到 None。

///|
test "split decimal string" {
  debug_inspect(@internal.split_decimal_string("-12.50e3"), content="Some((true, \"1250\", 1))")
  debug_inspect(@internal.split_decimal_string(".5"), content="Some((false, \"5\", -1))")
  debug_inspect(@internal.split_decimal_string("1e"), content="None")
}

Result 组合子

result_lift2, result_lift2_checked

这些函数组合两个 Result,返回第一个错误。

pub fn[A, B, E, C] result_lift2(Result[A, E], Result[B, E], (A, B) -> C) -> Result[C, E]
pub fn[A, B, E, C] result_lift2_checked(Result[A, E], Result[B, E], (A, B) -> Result[C, E]) -> Result[C, E]

result_lift2(Ok(a), Ok(b), f) 为 Ok(f(a, b));result_lift2_checked 则直接返回 f(a, b)。若 left 为 Err,则返回该错误;否则返回 right 中的 Err。

精确有理数

ExactRat

ExactRat 是一个最简形式的有理数。

pub struct ExactRat {
  // private fields
} derive(Eq)

ExactRat::new, ExactRat::numerator, ExactRat::denominator

ExactRat::new(n, d) 将 n/dn/d 约简为分母为正的最简形式;访问器返回约简后的各部分。

pub fn ExactRat::new(@bigint.BigInt, @bigint.BigInt) -> Self
pub fn ExactRat::numerator(Self) -> @bigint.BigInt
pub fn ExactRat::denominator(Self) -> @bigint.BigInt

当 d=0d = 0 时中止。零存储为 0/10/1。由于该形式是规范的,ExactRat 上的 == 就是有理数的相等。

ExactRat::equal, ExactRat::not_equal

这些方法比较规范形式;请使用 == 和 !=。

pub fn ExactRat::equal(Self, Self) -> Bool
pub fn ExactRat::not_equal(Self, Self) -> Bool
///|
test "exact rational" {
  let r = @internal.ExactRat::new(-6N, -8N)
  inspect(r.numerator(), content="3")
  inspect(r.denominator(), content="4")
  inspect(r == @internal.ExactRat::new(9N, 12N), content="true")
}

二进有理数包络

CertifiedDyadic

CertifiedDyadic 是二进有理数 n⋅2−sn \cdot 2^{-s},其中 nn 为 numerator_,标度 ss = scale_ 非负。

pub struct CertifiedDyadic {
  numerator_ : @bigint.BigInt
  scale_ : Int
}

这些字段可读;请用 new 或 from_int 构建值。

CertifiedDyadic::new, from_int, numerator, scale

new(n, s) 为 n⋅2−sn \cdot 2^{-s}(若 s<0s < 0 则中止);from_int(k) 为 k⋅20k \cdot 2^{0};访问器返回各字段。

pub fn CertifiedDyadic::new(@bigint.BigInt, Int) -> Self
pub fn CertifiedDyadic::from_int(Int) -> Self
pub fn CertifiedDyadic::numerator(Self) -> @bigint.BigInt
pub fn CertifiedDyadic::scale(Self) -> Int

该表示未经规范化:2⋅2−12 \cdot 2^{-1} 和 1⋅201 \cdot 2^{0} 是该结构体的两个不同的值,但表示同一个数。

CertifiedDyadic::add, sub, mul, neg, compare

这些方法是二进有理数的精确算术与比较。

pub fn CertifiedDyadic::add(Self, Self) -> Self
pub fn CertifiedDyadic::sub(Self, Self) -> Self
pub fn CertifiedDyadic::mul(Self, Self) -> Self
pub fn CertifiedDyadic::neg(Self) -> Self
pub fn CertifiedDyadic::compare(Self, Self) -> Int

add 和 sub 对齐到较大的标度;mul 将标度相加;compare 比较的是数值(而非表示)。

CertifiedDyadic::round_down, CertifiedDyadic::round_up

x.round_down(s) 和 x.round_up(s) 分别是标度为 ss 的二进有理数中 ≤x\le x 的最大者和 ≥x\ge x 的最小者:⌊x⋅2s⌋⋅2−s\lfloor x \cdot 2^{s} \rfloor \cdot 2^{-s} 与 ⌈x⋅2s⌉⋅2−s\lceil x \cdot 2^{s} \rceil \cdot 2^{-s}。

pub fn CertifiedDyadic::round_down(Self, Int) -> Self
pub fn CertifiedDyadic::round_up(Self, Int) -> Self

若 s<0s < 0 则中止。当 ss 不小于当前标度时,该值被精确地重新表示。

CertifiedInterval

CertifiedInterval[T] 是一个满足 lower <= upper 的有序对,用作包络。

pub struct CertifiedInterval[T] {
  lower_ : T
  upper_ : T
}
pub fn[T] CertifiedInterval::new(T, T, (T, T) -> Int) -> Result[Self[T], @arithmetic.ArithmeticError]
pub fn[T] CertifiedInterval::lower(Self[T]) -> T
pub fn[T] CertifiedInterval::upper(Self[T]) -> T

当 compare(lower, upper) > 0 时,new(lower, upper, compare) 返回一个认证失败错误,其阶段为 EnclosurePropagation,原因为 InvalidEnclosure。

certified_dyadic_fraction

certified_dyadic_fraction(n, d, s) 用两个标度为 ss 的二进有理数包络 n/dn/d。

pub fn certified_dyadic_fraction(@bigint.BigInt, @bigint.BigInt, Int) -> Result[CertifiedInterval[CertifiedDyadic], @arithmetic.ArithmeticError]

结果为 [⌊n2s/d⌋2−s, ⌈n2s/d⌉2−s][\lfloor n 2^{s}/d \rfloor 2^{-s},\ \lceil n 2^{s}/d \rceil 2^{-s}]:它包含 n/dn/d,宽度为 00 或 2−s2^{-s},且当且仅当 d∣n2sd \mid n 2^{s} 时为单点。非正的 dd 产生定义域错误。

certified_dyadic_div

certified_dyadic_div(a, b, s) 以标度 ss 包络两个二进有理数的商 a/ba/b。

pub fn certified_dyadic_div(CertifiedDyadic, CertifiedDyadic, Int) -> Result[CertifiedInterval[CertifiedDyadic], @arithmetic.ArithmeticError]

b=0b = 0 产生除以零错误。否则,结果是将 certified_dyadic_fraction 作用于写成正分母形式的 a/ba/b。

///|
test "one third at scale 8" {
  let third = @internal.certified_dyadic_div(
    @internal.CertifiedDyadic::from_int(1),
    @internal.CertifiedDyadic::from_int(3),
    8,
  ).unwrap()
  inspect(third.lower().numerator(), content="85") // 85/256 <= 1/3
  inspect(third.upper().numerator(), content="86") // 86/256 >= 1/3
}

细化预算

CertifiedRefinementBudget

CertifiedRefinementBudget 跟踪 Ziv 式求值循环的工作精度和细化次数。

pub struct CertifiedRefinementBudget {
  work_precision : Int
  refinements_ : Int
  limit_ : Int
}

CertifiedRefinementBudget::new, next, available, precision, refinements

new(p, limit?) 以工作精度 max⁡(1,p)\max(1, p)、零次细化开始,细化次数上限为 max⁡(1,limit)\max(1, \mathit{limit})(默认 12)。next() 将精度增加 max⁡(32,⌊p/2⌋)\max(32, \lfloor p/2 \rfloor),并计入一次细化。只要已进行的细化次数少于 limit,available() 就为真。

pub fn CertifiedRefinementBudget::new(Int, limit? : Int) -> Self
pub fn CertifiedRefinementBudget::next(Self) -> Self
pub fn CertifiedRefinementBudget::available(Self) -> Bool
pub fn CertifiedRefinementBudget::precision(Self) -> Int
pub fn CertifiedRefinementBudget::refinements(Self) -> Int

例如 64→96→144→21664 \to 96 \to 144 \to 216。

certified_failure

certified_failure(operation, stage, reason, target_precision, budget) 构建经认证运算放弃时返回的 ArithmeticError。

pub fn certified_failure(String, @arithmetic.CertificationStage, @arithmetic.CertificationFailureReason, Int, CertifiedRefinementBudget) -> @arithmetic.ArithmeticError

该错误的详情记录运算名、阶段、原因、目标精度,以及预算当前的工作精度和细化次数。

完整公共接口

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

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

import {
  "Luna-Flow/arithmetic",
  "Luna-Flow/floating/def",
  "moonbitlang/core/bigint",
}

// Values
pub fn abs_bigint(@bigint.BigInt) -> @bigint.BigInt

pub fn bigint_one() -> @bigint.BigInt

pub fn bigint_zero() -> @bigint.BigInt

pub fn certified_dyadic_div(CertifiedDyadic, CertifiedDyadic, Int) -> Result[CertifiedInterval[CertifiedDyadic], @arithmetic.ArithmeticError]

pub fn certified_dyadic_fraction(@bigint.BigInt, @bigint.BigInt, Int) -> Result[CertifiedInterval[CertifiedDyadic], @arithmetic.ArithmeticError]

pub fn certified_failure(String, @arithmetic.CertificationStage, @arithmetic.CertificationFailureReason, Int, CertifiedRefinementBudget) -> @arithmetic.ArithmeticError

pub fn compare_abs(@bigint.BigInt, @bigint.BigInt) -> Int

pub fn digits10(@bigint.BigInt) -> Int

pub fn exact_divide_by_power_of_ten(@bigint.BigInt, Int) -> @bigint.BigInt?

pub fn pow10(Int) -> @bigint.BigInt

pub fn pow2(Int) -> @bigint.BigInt

pub fn pow5(Int) -> @bigint.BigInt

pub fn remove_factor10(@bigint.BigInt, Int) -> (@bigint.BigInt, Int)

pub fn remove_factor2(@bigint.BigInt, Int) -> (@bigint.BigInt, Int)

pub fn[A, B, E, C] result_lift2(Result[A, E], Result[B, E], (A, B) -> C) -> Result[C, E]

pub fn[A, B, E, C] result_lift2_checked(Result[A, E], Result[B, E], (A, B) -> Result[C, E]) -> Result[C, E]

pub fn round_positive_div(@bigint.BigInt, @bigint.BigInt, Bool, @arithmetic.RoundingMode) -> @bigint.BigInt

pub fn round_shift(@bigint.BigInt, Int, Bool, @arithmetic.RoundingMode) -> @bigint.BigInt

pub fn sign_of_bigint(@bigint.BigInt) -> @def.Sign

pub fn split_decimal_string(String) -> (Bool, String, Int)?

pub fn trim_trailing_decimal_zeros(@bigint.BigInt, Int, max_drop? : Int) -> (@bigint.BigInt, Int, Int)

// Errors

// Types and methods
pub struct CertifiedDyadic {
  numerator_ : @bigint.BigInt
  scale_ : Int
}
pub fn CertifiedDyadic::add(Self, Self) -> Self
pub fn CertifiedDyadic::compare(Self, Self) -> Int
pub fn CertifiedDyadic::from_int(Int) -> Self
pub fn CertifiedDyadic::mul(Self, Self) -> Self
pub fn CertifiedDyadic::neg(Self) -> Self
pub fn CertifiedDyadic::new(@bigint.BigInt, Int) -> Self
pub fn CertifiedDyadic::numerator(Self) -> @bigint.BigInt
pub fn CertifiedDyadic::round_down(Self, Int) -> Self
pub fn CertifiedDyadic::round_up(Self, Int) -> Self
pub fn CertifiedDyadic::scale(Self) -> Int
pub fn CertifiedDyadic::sub(Self, Self) -> Self

pub struct CertifiedInterval[T] {
  lower_ : T
  upper_ : T
}
pub fn[T] CertifiedInterval::lower(Self[T]) -> T
pub fn[T] CertifiedInterval::new(T, T, (T, T) -> Int) -> Result[Self[T], @arithmetic.ArithmeticError]
pub fn[T] CertifiedInterval::upper(Self[T]) -> T

pub struct CertifiedRefinementBudget {
  work_precision : Int
  refinements_ : Int
  limit_ : Int
}
pub fn CertifiedRefinementBudget::available(Self) -> Bool
pub fn CertifiedRefinementBudget::new(Int, limit? : Int) -> Self
pub fn CertifiedRefinementBudget::next(Self) -> Self
pub fn CertifiedRefinementBudget::precision(Self) -> Int
pub fn CertifiedRefinementBudget::refinements(Self) -> Int

pub struct ExactRat {
  // private fields
} derive(Eq)
pub fn ExactRat::denominator(Self) -> @bigint.BigInt
pub fn ExactRat::equal(Self, Self) -> Bool
pub fn ExactRat::new(@bigint.BigInt, @bigint.BigInt) -> Self
pub fn ExactRat::not_equal(Self, Self) -> Bool
pub fn ExactRat::numerator(Self) -> @bigint.BigInt

// Type aliases

// Traits