ball_float_checked API

ball_float_checked 提供 BallFloatResult,它是用于区间计算的、对 Result[BallFloat, ArithmeticError] 的封闭包装。构造时会校验输入,每个运算都会传递遇到的第一个错误,当所有操作数都成功时则应用 ball_float 的区间运算。一个有效但不含信息的包络(空集、整条实轴)属于成功,而不是错误。该包装不存储装饰,也不存储 BallFlags。教程介绍如何构建计算管线;设计文档解释哪些结果属于错误及其原因。

示例使用以下辅助函数输出结果(有界球的 to_string 为精确二进制记法下的 centre +/- radius,mpe 表示 m⋅2em \cdot 2^{e}):

///|
fn show(r : @ball_float_checked.BallFloatResult) -> String {
  match r.result() {
    Ok(v) => v.to_string()
    Err(e) => "error: " + e.message
  }
}

包装类型

BallFloatResult

BallFloatResult 要么是成功的 BallFloat,要么是 ArithmeticError。

pub struct BallFloatResult {
  // private fields
}

唯一的私有字段保存一个 Result[@ball_float.BallFloat, @arithmetic.ArithmeticError]。该类型没有 Eq 或 Show;请使用 result()。

构造

BallFloatResult::ok, BallFloatResult::err, BallFloatResult::from_result

这些函数原样包装一个已有的区间、错误或 Result。

pub fn BallFloatResult::ok(@ball_float.BallFloat) -> Self
pub fn BallFloatResult::err(@arithmetic.ArithmeticError) -> Self
pub fn BallFloatResult::from_result(Result[@ball_float.BallFloat, @arithmetic.ArithmeticError]) -> Self

BallFloatResult::from_int, BallFloatResult::from_coefficient

这些构造函数通过 BallFloat::from_int / BallFloat::from_coefficient 由整数构建点区间;它们从不失败。

pub fn BallFloatResult::from_int(Int, precision? : Int) -> Self
pub fn BallFloatResult::from_coefficient(@bin_float.BinCoeff, precision? : Int, negative? : Bool) -> Self

默认精度为 16 位。整数先以就近舍入转换为 max⁡(precision,8)\max(\textit{precision}, 8) 位的 BinFloat,然后再被包络。

BallFloatResult::from_double, BallFloatResult::from_float

这些构造函数包络一个有限的 Double 或 Float。

pub fn BallFloatResult::from_double(Double, precision? : Int) -> Self
pub fn BallFloatResult::from_float(Float, precision? : Int) -> Self

源值先被精确转换(至少 53 或 24 位),然后向外舍入到 precision(默认分别为 53 和 24),因此结果总是包含源值。NaN 或无穷的源值给出 DomainError(ball double source must be finite、ball float source must be finite)。

BallFloatResult::exact

exact(x, precision~) 包络一个有限的 BinFloat。

pub fn BallFloatResult::exact(@bin_float.BinFloat, precision? : Int) -> Self

precision 默认为 x.precision()。两个界分别是 x 向下和向上舍入到该精度的结果,因此结果包含 x。非有限的 x 给出 DomainError(ball exact source must be finite)。

BallFloatResult::from_bounds

from_bounds(lo, hi, precision~) 构建区间 [lo,hi][\textit{lo}, \textit{hi}]。

pub fn BallFloatResult::from_bounds(@bin_float.BinFloat, @bin_float.BinFloat, precision? : Int) -> Self

precision 默认为两个界中较大的精度;lo 向下舍入,hi 向上舍入。当某个界为 NaN、lo 为 +∞+\infty、hi 为 −∞-\infty(IEEE 1788 区间是 R\mathbb{R} 的子集,因此 [+∞,+∞][+\infty, +\infty] 不是区间),或 lo > hi 时,返回 DomainError。开放一侧允许使用无穷界:[−∞,0][-\infty, 0] 是有效的。

BallFloatResult::whole

whole(precision~) 是整条实轴 [−∞,+∞][-\infty, +\infty](默认精度 53);它从不失败。

pub fn BallFloatResult::whole(precision? : Int) -> Self
///|
test "construction validates its inputs" {
  let one = @bin_float.BinFloat::from_int(1)
  let three = @bin_float.BinFloat::from_int(3)
  inspect(show(@ball_float_checked.BallFloatResult::from_bounds(one, three)), content="1p1 +/- 1p0")
  inspect(
    show(@ball_float_checked.BallFloatResult::from_bounds(three, one)),
    content="error: ball lower bound must not exceed upper bound",
  )
  inspect(
    show(@ball_float_checked.BallFloatResult::from_double(0.1, precision=8)),
    content="409p-12 +/- 1p-12",
  )
  inspect(
    show(@ball_float_checked.BallFloatResult::from_double(0.0 / 0.0)),
    content="error: ball double source must be finite",
  )
  let infinity = @bin_float.BinFloat::inf(@def.Sign::Positive)
  inspect(
    show(@ball_float_checked.BallFloatResult::from_bounds(infinity, infinity)),
    content="error: ball lower bound must not be positive infinity",
  )
  inspect(show(@ball_float_checked.BallFloatResult::whole()), content="[-inf, inf]")
}

观察

BallFloatResult::result, is_ok, is_err, error

这些方法暴露被包装的 Result、检测其分支,或以 option 形式返回错误。

pub fn BallFloatResult::result(Self) -> Result[@ball_float.BallFloat, @arithmetic.ArithmeticError]
pub fn BallFloatResult::is_ok(Self) -> Bool
pub fn BallFloatResult::is_err(Self) -> Bool
pub fn BallFloatResult::error(Self) -> @arithmetic.ArithmeticError?

当且仅当 result() 为 Err(e) 时,error() 为 Some(e)。

组合

BallFloatResult::map, BallFloatResult::bind

map(f) 将一个不会失败的区间函数应用于成功值;bind(f) 应用一个可能失败的函数。错误原样传递。

pub fn BallFloatResult::map(Self, (@ball_float.BallFloat) -> @ball_float.BallFloat) -> Self
pub fn BallFloatResult::bind(Self, (@ball_float.BallFloat) -> Self) -> Self

它们满足 bin_float_checked 设计文档中证明的 monad 定律与 functor 定律;该证明不依赖于值的类型。

一元值映射

neg, abs, normalized, with_precision

这些方法是对同名 BallFloat 方法的 map。

pub fn BallFloatResult::neg(Self) -> Self
pub fn BallFloatResult::abs(Self) -> Self
pub fn BallFloatResult::normalized(Self) -> Self
pub fn BallFloatResult::with_precision(Self, Int, @arithmetic.RoundingMode) -> Self

neg 和 abs 是精确的区间像 {−t}\{-t\} 和 {∣t∣}\{|t|\};with_precision 对每种舍入模式都返回输入在新精度下的包络(模式只影响中心)。

算术

add, sub, mul, div

这些方法用 BallFloat 运算符组合两个包装值。

pub fn BallFloatResult::add(Self, Self) -> Self
pub fn BallFloatResult::sub(Self, Self) -> Self
pub fn BallFloatResult::mul(Self, Self) -> Self
pub fn BallFloatResult::div(Self, Self) -> Self

左操作数的错误优先,其次是右操作数的。区间算术本身从不失败:结果包络 { s∘t:s∈X,t∈Y }\{\, s \circ t : s \in X, t \in Y \,\}。除以恰为 {0}\{0\} 的区间得到空集,除以内部包含零的区间得到整条实轴。

pow_nat, pow_int

这些方法通过 Luna-Flow/arithmetic 的 trait PowNatChecked 和 PowIntChecked 计算区间的整数次幂。

pub fn BallFloatResult::pow_nat(Self, UInt) -> Self
pub fn BallFloatResult::pow_int(Self, Int) -> Self

上下文为 ArithmeticContext::new(x.precision());ball_float 只使用其精度。结果是 {tn}\{t^{n}\} 的包络,按幂运算计算(因此 [1,3][1, 3] 的 pow_int(2) 为 [1,9][1, 9];对于包含零的区间,它比 x * x 更紧)。零底数配负指数给出空集。

rootn

rootn(n) 用 BallFloat::try_rootn 包络实 nn 次方根。

pub fn BallFloatResult::rootn(Self, Int) -> Self

次数 00 给出 DomainError。偶次方根忽略区间的负值部分(集合语义):[−1,1][-1, 1] 的方根为 [0,1][0, 1]。

pow, hypot, atan2

这些二元函数包络 xyx^{y}、x2+y2\sqrt{x^2+y^2} 以及 (abscissa,self)(\text{abscissa}, \text{self}) 的辐角。

pub fn BallFloatResult::pow(Self, Self) -> Self
pub fn BallFloatResult::hypot(Self, Self) -> Self
pub fn BallFloatResult::atan2(Self, Self) -> Self

它们调用 try_pow_interval、try_hypot 和 try_atan2_interval。操作数错误先取左侧;运算本身可能以 CertificationFailure 失败。实定义域之外的点会从结果集合中去除,因此 (−2)0.5(-2)^{0.5} 是空区间。

///|
test "interval arithmetic in the wrapper" {
  let x = @ball_float_checked.BallFloatResult::from_bounds(
    @bin_float.BinFloat::from_int(1),
    @bin_float.BinFloat::from_int(3),
  )
  inspect(show(x * x - x), content="3p0 +/- 5p0")
  inspect(show(x.pow_int(2)), content="5p0 +/- 1p2")
  let one = @ball_float_checked.BallFloatResult::from_int(1)
  let zero = @ball_float_checked.BallFloatResult::from_int(0)
  inspect(show(one / zero), content="[empty]")
  let around_zero = @ball_float_checked.BallFloatResult::from_bounds(
    @bin_float.BinFloat::from_int(-1),
    @bin_float.BinFloat::from_int(1),
  )
  inspect(show(one / around_zero), content="[-inf, inf]")
  inspect(show(around_zero.rootn(2)), content="1p-1 +/- 1p-1")
  inspect(show(x.rootn(0)), content="error: rootn degree must not be zero")
}

初等函数

指数、对数、三角与双曲函数

exp、exp2、exp10、expm1、ln、log2、log10、log1p、sin、cos、tan、sinpi、cospi、tanpi、asin、acos、atan、sinh、cosh、tanh、asinh、acosh 和 atanh 包络区间在该函数下的像。

pub fn BallFloatResult::exp(Self) -> Self
pub fn BallFloatResult::exp2(Self) -> Self
pub fn BallFloatResult::exp10(Self) -> Self
pub fn BallFloatResult::expm1(Self) -> Self
pub fn BallFloatResult::ln(Self) -> Self
pub fn BallFloatResult::log2(Self) -> Self
pub fn BallFloatResult::log10(Self) -> Self
pub fn BallFloatResult::log1p(Self) -> Self
pub fn BallFloatResult::sin(Self) -> Self
pub fn BallFloatResult::cos(Self) -> Self
pub fn BallFloatResult::tan(Self) -> Self
pub fn BallFloatResult::sinpi(Self) -> Self
pub fn BallFloatResult::cospi(Self) -> Self
pub fn BallFloatResult::tanpi(Self) -> Self
pub fn BallFloatResult::asin(Self) -> Self
pub fn BallFloatResult::acos(Self) -> Self
pub fn BallFloatResult::atan(Self) -> Self
pub fn BallFloatResult::sinh(Self) -> Self
pub fn BallFloatResult::cosh(Self) -> Self
pub fn BallFloatResult::tanh(Self) -> Self
pub fn BallFloatResult::asinh(Self) -> Self
pub fn BallFloatResult::acosh(Self) -> Self
pub fn BallFloatResult::atanh(Self) -> Self

每个方法都是以区间精度对 BallFloat::try_<name>_interval 进行 bind。结果 YY 满足 f(X∩dom⁡f)⊆Yf(X \cap \operatorname{dom} f) \subseteq Y;XX 中位于定义域之外的部分被忽略,因此 ln⁡([−1,1])=[−∞,0]\ln([-1, 1]) = [-\infty, 0],而 ln⁡([−2,−2])\ln([-2, -2]) 为空。唯一的错误是无法认证包络时的 CertificationFailure,例如 2700002^{70000} 的余弦(原因为 ResourceLimit)。没有上下文变体;精度通过 with_precision 设置。

///|
test "elementary enclosures" {
  let two = @ball_float_checked.BallFloatResult::from_int(2, precision=53)
  inspect(show(two.ln()), content="12486629536330719p-54 +/- 1p-54")
  inspect(show(two.ln().exp()), content="18014398509481985p-53 +/- 3p-53")
  let around_zero = @ball_float_checked.BallFloatResult::from_bounds(
    @bin_float.BinFloat::from_int(-1),
    @bin_float.BinFloat::from_int(1),
  )
  inspect(show(around_zero.ln()), content="[-inf, 0]")
  let huge = @ball_float_checked.BallFloatResult::exact(
    @bin_float.BinFloat::make(@bin_float.BinCoeff::one(), 70000, 53),
  )
  match huge.cos().error() {
    Some(e) => {
      let detail = e.certification_failure_detail().unwrap()
      inspect(detail.operation(), content="cos")
      inspect(
        detail.reason() == @lf_arith.CertificationFailureReason::ResourceLimit,
        content="true",
      )
    }
    None => fail("expected a certification failure")
  }
}

trait 实现

Add, Sub, Mul, Div, Neg

运算符 +、-、*、/ 和一元 - 调用 add、sub、mul、div 和 neg。

pub impl Add for BallFloatResult
pub impl Sub for BallFloatResult
pub impl Mul for BallFloatResult
pub impl Neg for BallFloatResult
pub impl Div for BallFloatResult

已弃用

BallFloatResult::flat_map

flat_map 是 bind 的旧名称。请将 r.flat_map(f) 替换为 r.bind(f)。

#deprecated
pub fn BallFloatResult::flat_map(Self, (@ball_float.BallFloat) -> Self) -> Self

完整公共接口

以下快照是该包完整的生成接口。

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

import {
  "Luna-Flow/arithmetic",
  "Luna-Flow/floating/ball_float",
  "Luna-Flow/floating/bin_float",
}

// Values

// Errors

// Types and methods
pub struct BallFloatResult {
  // private fields
}
pub fn BallFloatResult::abs(Self) -> Self
pub fn BallFloatResult::acos(Self) -> Self
pub fn BallFloatResult::acosh(Self) -> Self
pub fn BallFloatResult::add(Self, Self) -> Self
pub fn BallFloatResult::asin(Self) -> Self
pub fn BallFloatResult::asinh(Self) -> Self
pub fn BallFloatResult::atan(Self) -> Self
pub fn BallFloatResult::atan2(Self, Self) -> Self
pub fn BallFloatResult::atanh(Self) -> Self
pub fn BallFloatResult::bind(Self, (@ball_float.BallFloat) -> Self) -> Self
pub fn BallFloatResult::cos(Self) -> Self
pub fn BallFloatResult::cosh(Self) -> Self
pub fn BallFloatResult::cospi(Self) -> Self
pub fn BallFloatResult::div(Self, Self) -> Self
pub fn BallFloatResult::err(@arithmetic.ArithmeticError) -> Self
pub fn BallFloatResult::error(Self) -> @arithmetic.ArithmeticError?
pub fn BallFloatResult::exact(@bin_float.BinFloat, precision? : Int) -> Self
pub fn BallFloatResult::exp(Self) -> Self
pub fn BallFloatResult::exp10(Self) -> Self
pub fn BallFloatResult::exp2(Self) -> Self
pub fn BallFloatResult::expm1(Self) -> Self
#deprecated
pub fn BallFloatResult::flat_map(Self, (@ball_float.BallFloat) -> Self) -> Self
pub fn BallFloatResult::from_bounds(@bin_float.BinFloat, @bin_float.BinFloat, precision? : Int) -> Self
pub fn BallFloatResult::from_coefficient(@bin_float.BinCoeff, precision? : Int, negative? : Bool) -> Self
pub fn BallFloatResult::from_double(Double, precision? : Int) -> Self
pub fn BallFloatResult::from_float(Float, precision? : Int) -> Self
pub fn BallFloatResult::from_int(Int, precision? : Int) -> Self
pub fn BallFloatResult::from_result(Result[@ball_float.BallFloat, @arithmetic.ArithmeticError]) -> Self
pub fn BallFloatResult::hypot(Self, Self) -> Self
pub fn BallFloatResult::is_err(Self) -> Bool
pub fn BallFloatResult::is_ok(Self) -> Bool
pub fn BallFloatResult::ln(Self) -> Self
pub fn BallFloatResult::log10(Self) -> Self
pub fn BallFloatResult::log1p(Self) -> Self
pub fn BallFloatResult::log2(Self) -> Self
pub fn BallFloatResult::map(Self, (@ball_float.BallFloat) -> @ball_float.BallFloat) -> Self
pub fn BallFloatResult::mul(Self, Self) -> Self
pub fn BallFloatResult::neg(Self) -> Self
pub fn BallFloatResult::normalized(Self) -> Self
pub fn BallFloatResult::ok(@ball_float.BallFloat) -> Self
pub fn BallFloatResult::pow(Self, Self) -> Self
pub fn BallFloatResult::pow_int(Self, Int) -> Self
pub fn BallFloatResult::pow_nat(Self, UInt) -> Self
pub fn BallFloatResult::result(Self) -> Result[@ball_float.BallFloat, @arithmetic.ArithmeticError]
pub fn BallFloatResult::rootn(Self, Int) -> Self
pub fn BallFloatResult::sin(Self) -> Self
pub fn BallFloatResult::sinh(Self) -> Self
pub fn BallFloatResult::sinpi(Self) -> Self
pub fn BallFloatResult::sub(Self, Self) -> Self
pub fn BallFloatResult::tan(Self) -> Self
pub fn BallFloatResult::tanh(Self) -> Self
pub fn BallFloatResult::tanpi(Self) -> Self
pub fn BallFloatResult::whole(precision? : Int) -> Self
pub fn BallFloatResult::with_precision(Self, Int, @arithmetic.RoundingMode) -> Self
pub impl Add for BallFloatResult
pub impl Div for BallFloatResult
pub impl Mul for BallFloatResult
pub impl Neg for BallFloatResult
pub impl Sub for BallFloatResult

// Type aliases

// Traits