decimal_checked API
decimal_checked 提供 DecimalChecked,这是基于 decimal 的 IEEE 754 十进制算术的不可变流水线状态。该状态保存当前值、一个 DecimalContext、最近一步引发的标志、所有步骤累积的标志,以及一个可选的 ArithmeticError。每个运算都在所存储的上下文下执行对应的 Decimal::*_ctx 运算。IEEE 异常结果(无穷、NaN、舍入后的值)仍然是值,只设置标志;只有当初等函数无法认证其结果时才记录错误,并使流水线停止。教程展示了典型的流水线;设计页面将该状态建模为标志幺半群上的 writer 单子,并证明累积标志是各步标志的并。
示例使用如下辅助函数列出标志:
///|
fn flags(f : @decimal.DecimalFlags) -> String {
let named = [
("inexact", f.inexact),
("rounded", f.rounded),
("invalid_operation", f.invalid_operation),
("division_by_zero", f.division_by_zero),
("overflow", f.overflow),
("underflow", f.underflow),
("subnormal", f.subnormal),
("conversion_syntax", f.conversion_syntax),
("invalid_context", f.invalid_context),
]
[ for p in named if p.1 => p.0 ].join(",")
}
状态类型
DecimalChecked
DecimalChecked 是 IEEE 十进制流水线的状态。
pub struct DecimalChecked {
// private fields
}
将状态记为 :值 、上下文 、最近一步引发的标志 、累积标志 ,以及错误 (不存在或为一个 ArithmeticError)。每个运算都返回新的状态;不修改任何东西。
构造
DecimalChecked::from_outcome
from_outcome(value, context, flags) 由一个值及产生它的标志开始一条流水线。
pub fn DecimalChecked::from_outcome(@decimal.Decimal, @decimal.DecimalContext, @decimal.DecimalFlags) -> Self
结果为 ,其中 (在当前分支上 ieee754() 原样返回上下文)。值不会被重新舍入;请将它与 Decimal::*_ctx 调用返回的 (value, flags) 二元组配合使用。
DecimalChecked::from_decimal
from_decimal(value, context) 将值舍入到上下文中。
pub fn DecimalChecked::from_decimal(@decimal.Decimal, @decimal.DecimalContext) -> Self
它执行 Decimal::apply_ctx,将值舍入到上下文的精度和指数范围,并把所得标志同时记录为引发标志和累积标志。
DecimalChecked::parse
parse(source, context) 在上下文下转换十进制字符串。
pub fn DecimalChecked::parse(String, @decimal.DecimalContext) -> Self
它使用 Decimal::from_string_ctx。多余的数字会被舍入(inexact、rounded);无效字符串得到一个 NaN 值并引发 conversion_syntax,而不是错误。
DecimalChecked::from_int, from_bigint, from_double, from_float
这些构造函数转换 MoonBit 数值。
pub fn DecimalChecked::from_int(Int, @decimal.DecimalContext) -> Self
pub fn DecimalChecked::from_bigint(@bigint.BigInt, @decimal.DecimalContext) -> Self
pub fn DecimalChecked::from_double(Double, @decimal.DecimalContext) -> Self
pub fn DecimalChecked::from_float(Float, @decimal.DecimalContext) -> Self
from_int 和 from_bigint 解析整数的十进制字符串,因此长于精度的整数会被舍入并带有标志。from_double 先将二进制值转换为 17 位有效数字的十进制数,from_float 则转换为 9 位(足以唯一确定该二进制值),然后用 from_decimal 舍入到上下文中。因此 from_double(0.1, decimal64) 为 0.1000000000000000,并引发 inexact 和 rounded。
///|
test "construction records conversion flags" {
let ctx = @decimal.DecimalContext::new(precision=5)
let parsed = @decimal_checked.DecimalChecked::parse("1.234567", ctx)
inspect(parsed.value().to_string(), content="1.2346")
inspect(flags(parsed.raised()), content="inexact,rounded")
let bad = @decimal_checked.DecimalChecked::parse("abc", ctx)
inspect(bad.value().to_string(), content="nan")
inspect(bad.is_ok(), content="true")
inspect(
flags(bad.raised()).contains("conversion_syntax"),
content="true",
)
let tenth = @decimal_checked.DecimalChecked::from_double(
0.1,
@decimal.DecimalContext::decimal64(),
)
inspect(tenth.value().to_string(), content="0.1000000000000000")
}
观察
value, context, raised, flags
这些访问函数返回状态的各个分量。
pub fn DecimalChecked::value(Self) -> @decimal.Decimal
pub fn DecimalChecked::context(Self) -> @decimal.DecimalContext
pub fn DecimalChecked::raised(Self) -> @decimal.DecimalFlags
pub fn DecimalChecked::flags(Self) -> @decimal.DecimalFlags
raised() 即 ,仅为最近一次成功步骤的标志。flags() 即 ,是自构造或上次 clear_flags 以来所有成功步骤标志的按位 OR。出错之后,value、raised 和 flags 保持失败步骤之前所达到的状态。
outcome, result
这些方法返回值及累积标志。
pub fn DecimalChecked::outcome(Self) -> (@decimal.Decimal, @decimal.DecimalFlags)
pub fn DecimalChecked::result(Self) -> Result[(@decimal.Decimal, @decimal.DecimalFlags), @arithmetic.ArithmeticError]
outcome() 无论是否有错误都为 ;result() 在记录了错误时为 ,否则为 。
is_ok, is_err, error
这些方法检测并返回所记录的错误。
pub fn DecimalChecked::is_ok(Self) -> Bool
pub fn DecimalChecked::is_err(Self) -> Bool
pub fn DecimalChecked::error(Self) -> @arithmetic.ArithmeticError?
控制状态
DecimalChecked::clear_flags
clear_flags() 将 和 都重置为空标志集。
pub fn DecimalChecked::clear_flags(Self) -> Self
值、上下文与错误保持不变。它同样适用于带有错误的状态。
DecimalChecked::with_context
with_context(context) 切换到新的上下文,并将当前值舍入到其中。
pub fn DecimalChecked::with_context(Self, @decimal.DecimalContext) -> Self
值在新上下文下用 apply_ctx 重新应用;新的标志成为 ,并 OR 到 中。对带有错误的状态,它原样返回该状态。
DecimalChecked::apply
apply() 将当前值舍入到所存储的上下文中,并记录标志。
pub fn DecimalChecked::apply(Self) -> Self
///|
test "raised versus accumulated flags" {
let ctx = @decimal.DecimalContext::new(precision=5)
let start = @decimal_checked.DecimalChecked::parse("1.234567", ctx)
let step = start.add(@decimal.Decimal::from_int(1))
inspect(flags(step.raised()), content="")
inspect(flags(step.flags()), content="inexact,rounded")
let infinite = step.div(@decimal.Decimal::zero())
inspect(infinite.value().to_string(), content="inf")
inspect(flags(infinite.raised()), content="division_by_zero")
inspect(flags(infinite.flags()), content="inexact,rounded,division_by_zero")
inspect(flags(infinite.clear_flags().flags()), content="")
let wider = @decimal_checked.DecimalChecked::parse(
"1.234567",
@decimal.DecimalContext::decimal64(),
).with_context(ctx)
inspect(wider.value().to_string(), content="1.2346")
}
不会失败的运算
plus, minus, abs, add, sub, mul, div, fma, sqrt, quantize, remainder, reduce, min, max, next_minus, next_plus, next_toward
这些方法在所存储的上下文下,对当前值和一个普通 Decimal 操作数执行含义相同的 IEEE 十进制运算。
pub fn DecimalChecked::plus(Self) -> Self
pub fn DecimalChecked::minus(Self) -> Self
pub fn DecimalChecked::abs(Self) -> Self
pub fn DecimalChecked::add(Self, @decimal.Decimal) -> Self
pub fn DecimalChecked::sub(Self, @decimal.Decimal) -> Self
pub fn DecimalChecked::mul(Self, @decimal.Decimal) -> Self
pub fn DecimalChecked::div(Self, @decimal.Decimal) -> Self
pub fn DecimalChecked::fma(Self, @decimal.Decimal, @decimal.Decimal) -> Self
pub fn DecimalChecked::sqrt(Self) -> Self
pub fn DecimalChecked::quantize(Self, @decimal.Decimal) -> Self
pub fn DecimalChecked::remainder(Self, @decimal.Decimal) -> Self
pub fn DecimalChecked::reduce(Self) -> Self
pub fn DecimalChecked::min(Self, @decimal.Decimal) -> Self
pub fn DecimalChecked::max(Self, @decimal.Decimal) -> Self
pub fn DecimalChecked::next_minus(Self) -> Self
pub fn DecimalChecked::next_plus(Self) -> Self
pub fn DecimalChecked::next_toward(Self, @decimal.Decimal) -> Self
| 方法 | 委托给 | 结果 |
|---|---|---|
plus, minus, abs | plus_ctx, minus_ctx, abs_ctx | 舍入到上下文的 、、 |
add, sub, mul, div | add_ctx, … | 正确舍入的 |
fma(m, a) | fma_ctx | 只舍入一次的 |
sqrt | sqrt_ctx | 正确舍入的 |
quantize(q) | quantize | 舍入到 q 的指数的 |
remainder(d) | remainder_ctx | |
reduce | reduce_ctx | 去除尾随零后的 |
min, max | min_ctx, max_ctx | IEEE 最小值 / 最大值 |
next_minus, next_plus, next_toward(t) | 同名 | 相邻的可表示值 |
若已记录错误,每个方法都原样返回状态。否则,步骤 给出新状态 。与 IEEE 754 十进制算术一致:无效运算产生带 invalid_operation 的 NaN,除以零产生带 division_by_zero 的无穷,上溢产生无穷或最大有限数,并带 overflow、inexact 和 rounded。
///|
test "exceptional results are values" {
let ctx = @decimal.DecimalContext::decimal64()
let negative = @decimal_checked.DecimalChecked::from_int(-1, ctx).sqrt()
inspect(negative.value().to_string(), content="nan")
inspect(flags(negative.raised()), content="invalid_operation")
inspect(negative.is_ok(), content="true")
let big = @decimal_checked.DecimalChecked::parse("9e384", ctx).mul(
@decimal.Decimal::from_int(10),
)
inspect(big.value().to_string(), content="inf")
inspect(flags(big.raised()), content="inexact,rounded,overflow")
let cents = @decimal_checked.DecimalChecked::parse("2.675", ctx).quantize(
@decimal.Decimal::from_string("0.01").unwrap(),
)
inspect(cents.value().to_string(), content="2.68")
}
可能记录错误的运算
初等函数
exp、exp2、exp10、expm1、ln、log2、log10、log1p、power、pown、rootn、hypot、sin、cos、tan、sinpi、cospi、tanpi、asin、acos、atan、atan2、sinh、cosh、tanh、asinh、acosh 和 atanh 应用经过认证的 Decimal::try_*_ctx 函数。
pub fn DecimalChecked::exp(Self) -> Self
pub fn DecimalChecked::exp2(Self) -> Self
pub fn DecimalChecked::exp10(Self) -> Self
pub fn DecimalChecked::expm1(Self) -> Self
pub fn DecimalChecked::ln(Self) -> Self
pub fn DecimalChecked::log2(Self) -> Self
pub fn DecimalChecked::log10(Self) -> Self
pub fn DecimalChecked::log1p(Self) -> Self
pub fn DecimalChecked::power(Self, @decimal.Decimal) -> Self
pub fn DecimalChecked::pown(Self, Int) -> Self
pub fn DecimalChecked::rootn(Self, Int) -> Self
pub fn DecimalChecked::hypot(Self, @decimal.Decimal) -> Self
pub fn DecimalChecked::sin(Self) -> Self
pub fn DecimalChecked::cos(Self) -> Self
pub fn DecimalChecked::tan(Self) -> Self
pub fn DecimalChecked::sinpi(Self) -> Self
pub fn DecimalChecked::cospi(Self) -> Self
pub fn DecimalChecked::tanpi(Self) -> Self
pub fn DecimalChecked::asin(Self) -> Self
pub fn DecimalChecked::acos(Self) -> Self
pub fn DecimalChecked::atan(Self) -> Self
pub fn DecimalChecked::atan2(Self, @decimal.Decimal) -> Self
pub fn DecimalChecked::sinh(Self) -> Self
pub fn DecimalChecked::cosh(Self) -> Self
pub fn DecimalChecked::tanh(Self) -> Self
pub fn DecimalChecked::asinh(Self) -> Self
pub fn DecimalChecked::acosh(Self) -> Self
pub fn DecimalChecked::atanh(Self) -> Self
结果被正确舍入到上下文中。定义域违例是带标志的 IEEE 值(负数的 ln 是带 invalid_operation 的 NaN,tanpi(0.5) 是带 division_by_zero 的无穷)。只有当 try_*_ctx 返回 Err 时才记录错误,这些函数在发生 CertificationFailure(无法在细化预算内认证正确舍入的结果)时会如此。出错时新状态为 :保留该步骤之前的值和标志。
///|
test "elementary functions under a bounded context" {
let ctx = @decimal.DecimalContext::decimal64()
let ln2 = @decimal_checked.DecimalChecked::from_int(2, ctx).ln()
inspect(ln2.value().to_string(), content="0.6931471805599453")
inspect(flags(ln2.raised()), content="inexact,rounded")
let unbounded = @decimal_checked.DecimalChecked::from_int(
2,
@decimal.DecimalContext::new(precision=16),
).ln()
inspect(unbounded.value().to_string(), content="nan")
inspect(flags(unbounded.raised()), content="invalid_context")
let pole = @decimal_checked.DecimalChecked::parse("0.5", ctx).tanpi()
inspect(flags(pole.raised()), content="division_by_zero")
}
完整公共接口
以下快照是该包完整的生成接口。
// Generated using `moon info`, DON'T EDIT IT
package "Luna-Flow/floating/decimal_checked"
import {
"Luna-Flow/arithmetic",
"Luna-Flow/floating/decimal",
"moonbitlang/core/bigint",
}
// Values
// Errors
// Types and methods
pub struct DecimalChecked {
// private fields
}
pub fn DecimalChecked::abs(Self) -> Self
pub fn DecimalChecked::acos(Self) -> Self
pub fn DecimalChecked::acosh(Self) -> Self
pub fn DecimalChecked::add(Self, @decimal.Decimal) -> Self
pub fn DecimalChecked::apply(Self) -> Self
pub fn DecimalChecked::asin(Self) -> Self
pub fn DecimalChecked::asinh(Self) -> Self
pub fn DecimalChecked::atan(Self) -> Self
pub fn DecimalChecked::atan2(Self, @decimal.Decimal) -> Self
pub fn DecimalChecked::atanh(Self) -> Self
pub fn DecimalChecked::clear_flags(Self) -> Self
pub fn DecimalChecked::context(Self) -> @decimal.DecimalContext
pub fn DecimalChecked::cos(Self) -> Self
pub fn DecimalChecked::cosh(Self) -> Self
pub fn DecimalChecked::cospi(Self) -> Self
pub fn DecimalChecked::div(Self, @decimal.Decimal) -> Self
pub fn DecimalChecked::error(Self) -> @arithmetic.ArithmeticError?
pub fn DecimalChecked::exp(Self) -> Self
pub fn DecimalChecked::exp10(Self) -> Self
pub fn DecimalChecked::exp2(Self) -> Self
pub fn DecimalChecked::expm1(Self) -> Self
pub fn DecimalChecked::flags(Self) -> @decimal.DecimalFlags
pub fn DecimalChecked::fma(Self, @decimal.Decimal, @decimal.Decimal) -> Self
pub fn DecimalChecked::from_bigint(@bigint.BigInt, @decimal.DecimalContext) -> Self
pub fn DecimalChecked::from_decimal(@decimal.Decimal, @decimal.DecimalContext) -> Self
pub fn DecimalChecked::from_double(Double, @decimal.DecimalContext) -> Self
pub fn DecimalChecked::from_float(Float, @decimal.DecimalContext) -> Self
pub fn DecimalChecked::from_int(Int, @decimal.DecimalContext) -> Self
pub fn DecimalChecked::from_outcome(@decimal.Decimal, @decimal.DecimalContext, @decimal.DecimalFlags) -> Self
pub fn DecimalChecked::hypot(Self, @decimal.Decimal) -> Self
pub fn DecimalChecked::is_err(Self) -> Bool
pub fn DecimalChecked::is_ok(Self) -> Bool
pub fn DecimalChecked::ln(Self) -> Self
pub fn DecimalChecked::log10(Self) -> Self
pub fn DecimalChecked::log1p(Self) -> Self
pub fn DecimalChecked::log2(Self) -> Self
pub fn DecimalChecked::max(Self, @decimal.Decimal) -> Self
pub fn DecimalChecked::min(Self, @decimal.Decimal) -> Self
pub fn DecimalChecked::minus(Self) -> Self
pub fn DecimalChecked::mul(Self, @decimal.Decimal) -> Self
pub fn DecimalChecked::next_minus(Self) -> Self
pub fn DecimalChecked::next_plus(Self) -> Self
pub fn DecimalChecked::next_toward(Self, @decimal.Decimal) -> Self
pub fn DecimalChecked::outcome(Self) -> (@decimal.Decimal, @decimal.DecimalFlags)
pub fn DecimalChecked::parse(String, @decimal.DecimalContext) -> Self
pub fn DecimalChecked::plus(Self) -> Self
pub fn DecimalChecked::power(Self, @decimal.Decimal) -> Self
pub fn DecimalChecked::pown(Self, Int) -> Self
pub fn DecimalChecked::quantize(Self, @decimal.Decimal) -> Self
pub fn DecimalChecked::raised(Self) -> @decimal.DecimalFlags
pub fn DecimalChecked::reduce(Self) -> Self
pub fn DecimalChecked::remainder(Self, @decimal.Decimal) -> Self
pub fn DecimalChecked::result(Self) -> Result[(@decimal.Decimal, @decimal.DecimalFlags), @arithmetic.ArithmeticError]
pub fn DecimalChecked::rootn(Self, Int) -> Self
pub fn DecimalChecked::sin(Self) -> Self
pub fn DecimalChecked::sinh(Self) -> Self
pub fn DecimalChecked::sinpi(Self) -> Self
pub fn DecimalChecked::sqrt(Self) -> Self
pub fn DecimalChecked::sub(Self, @decimal.Decimal) -> Self
pub fn DecimalChecked::tan(Self) -> Self
pub fn DecimalChecked::tanh(Self) -> Self
pub fn DecimalChecked::tanpi(Self) -> Self
pub fn DecimalChecked::value(Self) -> @decimal.Decimal
pub fn DecimalChecked::with_context(Self, @decimal.DecimalContext) -> Self
// Type aliases
// Traits