数值语义
本指南确立手册其余各页共用的数值术语。它区分五个容易混淆的概念:值的存储表示、运算所定义的精确值、上下文返回的舍入结果、舍入引发的状态,以及区间所保证的包络。每一节先给出定义,再推导库所依赖的性质,并配以可运行的示例。
值与表示
有限二进制值是一个带符号的整数系数乘以二的幂,有限十进制值则是乘以十的幂:
三元组 是表示;实数 是值。多个表示可以对应同一个值: 与 都是 。两种基数以不同方式处理这种冗余。
BinFloat在构造有限值时总会去掉系数中末尾的二的因子,因此有限非零BinFloat的系数总是奇数。其打印形式c p e展示的正是这一规范对。Decimal(位于decimal与decimal_gda中)保留给定的指数。指数 称为量子(quantum),同一个值的全部表示构成它的同值类(cohort):12.3400、12.340与12.34是同一个值的三个同值类成员。
每个值还带有一个精度 :舍入结果可使用的基数位数。精度是元数据和舍入上界;它并不表示每一个存储的数位都是有效数字,也从不改变基数。
///|
test "representation versus value" {
// 6 * 2^-2 is stored as the canonical 3 * 2^-1.
let three_halves = @bin_float.BinFloat::make(
@bin_float.BinCoeff::from_uint64(6UL),
-2,
53,
)
inspect(three_halves, content="3p-1")
inspect(three_halves.to_shortest_string(), content="1.5")
// A decimal keeps its quantum until it is normalized explicitly.
let price = @decimal.Decimal::from_string("12.3400").unwrap()
inspect(price.quantum(), content="-4")
inspect(price.normalized(), content="12.34")
inspect(price.normalized().quantum(), content="-2")
inspect(price.compare(price.normalized()), content="0")
inspect(price.same_quantum(price.normalized()), content="false")
}
有限值之外还有特殊值:带符号的无穷 ,以及分为静默与信号两种的 NaN(“not a number”,非数),每个 NaN 都带有符号和载荷(payload)。classify 报告 Finite、Infinity 或 NaN;@def.is_finite、@def.is_nan、@def.is_infinite 与 @def.is_zero 适用于所有实现了 @def.Floating 的类型。
精确值与舍入结果
每个算术运算 首先定义一个精确值:无误差计算得到的实数 (或 、 等)。格式很少能恰好容纳它,因此上下文将其映射为一个可表示的舍入结果
其中 是上下文的舍入函数。若运算结果恰好如此——即精确值只舍入一次——则称该运算是正确舍入的。floating 中的每个算术运算、平方根、融合乘加、求余、转换与解析都是正确舍入的;初等函数借助认证细化同样是正确舍入的(参见架构)。
只舍入一次至关重要。融合乘加 fma_ctx 对 只舍入一次,而先 mul_ctx 再 add_ctx 则舍入两次。在 binary64 中取 , 并不恰好等于 ,只有融合形式能看出差别:
///|
test "one rounding versus two" {
let ctx = @bin_float.BinaryContext::binary64()
let tenth = @bin_float.BinFloat::from_double(0.1)
let ten = @bin_float.BinFloat::from_int(10)
let minus_one = @bin_float.BinFloat::from_int(-1)
let (fused, _) = tenth.fma_ctx(ten, minus_one, ctx)
inspect(fused, content="1p-54")
let (product, _) = tenth.mul_ctx(ten, ctx)
inspect(product, content="1p0")
}
融合结果 正是舍入后乘积的精确误差:乘积 比 大 ,而 mul_ctx 把这部分超出量舍掉了。
舍入函数
设 为上下文可表示的值集合,并添加 。对实数 ,定向舍入为
而就近舍入在 与 中选取更接近 的那个;出现平局( 恰在正中)时,要么取末位为偶数的候选(),要么取绝对值较大的候选()。11 IEEE 754-2019 第 4.3 条定义了 roundTiesToEven、roundTiesToAway、roundTowardPositive、roundTowardNegative 与 roundTowardZero。远离零舍入以及十进制的 “05up” 模式来自 General Decimal Arithmetic 规范(Cowlishaw)。 每个舍入函数都是单调的(),且保持 不变(对 有 );区间算术与经认证的初等函数所依赖的正是这两条性质。
各个领域用各自的枚举来命名这些函数:
| 函数 | BinaryRoundingMode | @lf_arith.RoundingMode | DecimalRoundingMode / GdaRoundingMode |
|---|---|---|---|
RoundTiesToEven | ToNearestEven | HalfEven | |
RoundTiesToAway | — | HalfUp | |
| 就近舍入,平局时向零 | — | — | HalfDown |
RoundTowardZero | TowardZero | Down | |
RoundTowardPositive | TowardPositive | Ceiling | |
RoundTowardNegative | TowardNegative | Floor | |
RoundAwayFromZero | AwayFromZero | Up | |
| 向零舍入,若保留的末位为 0 或 5 则改为远离零 | — | — | ZeroFiveUp |
with_precision(p, mode) 以新精度对值应用其中一个舍入函数。二进制的 是 ;取五位时截断形式为 ,下一位是 1 且其后还有非零位,因此就近舍入向上进位:
///|
test "rounding 0.1 to five bits" {
let tenth = @bin_float.BinFloat::from_double(0.1)
inspect(tenth.with_precision(5, @lf_arith.ToNearestEven), content="13p-7")
inspect(tenth.with_precision(5, @lf_arith.TowardZero), content="25p-8")
}
舍入到整数
舍入到整数值是同一构造,只是取 。BinFloat 提供固定方向的形式 floor()、ceil()、trunc()、round(就近,平局远离零)和 round_ties_even(就近,平局取偶);to_integral_value_ctx 使用上下文的方向且不引发标志,to_integral_exact_ctx 则在值发生变化时额外引发 inexact。整数转换 to_int_ctx、to_int64_ctx、to_uint_ctx 与 to_uint64_ctx 以相同方式舍入,对 NaN、无穷和超出范围的结果返回 None 并引发 invalid。结果保留零的符号:。
///|
test "rounding to integers" {
let x = @bin_float.BinFloat::from_double(2.5)
inspect(x.round(), content="3p0")
inspect(x.round_ties_even(), content="1p1")
inspect(x.floor(), content="1p1")
inspect(@bin_float.BinFloat::from_double(-0.3).ceil(), content="-0")
let (n, flags) = x.to_int_ctx(
@bin_float.BinaryContext::binary64(),
exact=true,
)
inspect(n == Some(2), content="true")
inspect(flags.inexact(), content="true")
}
ulp 与单位舍入误差
对基数 、精度 以及满足 的非零 ,末位单位(unit in the last place)是 附近 位值之间的间距:
BinFloat::ulp 在 下、以值自身的精度和无界指数范围计算它;对零返回 ,即 的 ulp。在有界上下文中,间距在次正规数阈值处(见下一节)不再缩小,因此那里极小值的 ulp 为 。
单位舍入误差 界定一次舍入的相对误差。取范围内满足 的 。两个相邻值 与 位于同一个 binade 中(或其中之一为 ),相距一个 ulp,因此
由此得到浮点算术的标准模型:22 N. J. Higham,Accuracy and Stability of Numerical Algorithms,第 2 版,SIAM 2002,§2.2。含 的下溢形式即该书定理 2.3;Goldberg 的 “What every computer scientist should know about floating-point arithmetic”(ACM Computing Surveys 23(1),1991)对二进制情形给出了相同的推导。
只要精确值既不在上溢范围内、也不低于正规范围,该模型就成立。低于正规范围时误差改为绝对误差:存在次正规数时,,其中 ,且就近舍入下 。对 binary64()有 ;对 decimal64()有 。
///|
test "ulp of one tenth" {
let ctx = @bin_float.BinaryContext::binary64()
let (tenth, _) = @bin_float.BinFloat::from_string_ctx("0.1", ctx).unwrap()
inspect(tenth, content="3602879701896397p-55")
// 0.1 lies in [2^-4, 2^-3), so ulp = 2^(-4 - 53 + 1).
inspect(tenth.ulp(), content="1p-56")
let (third, flags) = @bin_float.BinFloat::from_int(1).div_ctx(
@bin_float.BinFloat::from_int(3),
ctx,
)
inspect(third.to_shortest_string(), content="0.3333333333333333")
inspect(flags.inexact(), content="true")
let (digits, _) = third.to_decimal_string_ctx(20, ctx)
inspect(digits, content="3.3333333333333331483e-1")
}
上下文:精度、指数范围与微小性(tininess)
上下文确定 和舍入函数。没有任何包读取环境中的舍入模式;上下文只是一个普通的不可变参数。
BinaryContext包含精度 (比特数)、一个BinaryRoundingMode、针对首位的可选指数界 ,以及一个TininessDetection。正规值满足 ;低于 时,次正规数保持固定间距 (渐进下溢)。binary16、binary32、binary64与binary128是 IEEE 交换格式的预设。unbounded(p)以及缺省的界使用实现范围 ,且所有精度都以 比特为上限。超出实现范围的结果会被归类处理(按舍入方向上溢为无穷或最大有限值、下溢为零或最小次正规数),而绝不会以饱和的指数存储。- 普通二进制运算符(
add、sub、mul、div、+、-、*、/)在该无界上下文中以两个操作数中较大的精度进行就近舍入(偶数优先),并丢弃标志。 DecimalContext(IEEE)与GdaContext(GDA)包含以数位计的精度、舍入模式、针对调整指数 的 与 ,以及一个clamp开关。次正规数可使用的最小指数为 。设置clamp后,指数超过 的结果会以零填充并引发 clamped,这正是交换格式的要求。例如decimal64的参数为 、、。- **微小性(tininess)**决定一个极小结果何时算作下溢:舍入前检测比较精确值与 ,舍入后检测比较假定指数范围无界时的舍入值。IEEE 754 对二进制格式允许任一种方式;GDA 总是在舍入前检测。
标志、错误与包络
floating 通过四个互不替代的通道报告问题:
| 通道 | 载体 | 是否返回值? | 含义 |
|---|---|---|---|
| 状态标志 | 与结果并列的 BinaryFlags、DecimalFlags、BallFlags | 是,即 IEEE 所定义的值 | 在产生已定义结果的过程中出现了某种情况 |
| GDA 状态与陷阱 | GdaOutcome, GdaContext::status | 是,触发陷阱时也返回 | 粘滞的条件;已启用的陷阱会把结果标记为 Trapped |
| checked 错误 | Result[_, ArithmeticError]、*Result 包装类型 | 否 | 在 checked 契约下无法产生所请求的标量 |
| 包络 | BallFloat, BallFloatDecorated | 是,一个集合 | 所有可能的精确结果都落在返回的区间内 |
IEEE 标志
五种 IEEE 异常33 IEEE 754-2019 第 7 条。默认异常处理返回此处列出的值并引发状态标志;floating 恰好实现这一默认行为,从不改变控制流。 在 BinaryFlags 中以布尔值报告,在 DecimalFlags 中以 DecimalSignal 成员报告:
- invalid operation(无效运算):不存在有意义的实数结果(、、、对信号 NaN 的任何运算);结果为静默 NaN。
- division by zero(除以零):由有限操作数得到精确的无穷结果(、)。
- overflow(上溢):在无界指数下的舍入结果将超过最大有限值;按舍入方向,结果为 或最大有限值,并同时引发 inexact。
- underflow(下溢):结果是微小的(按上下文的微小性规则)且不精确。
- inexact(不精确):舍入结果与精确值不同。
Decimal 另外增加了 GDA 条件 rounded(丢弃了数位,即使丢弃的是零)、clamped、subnormal、conversion syntax、division impossible、division undefined、invalid context 与 lost digits。标志从不取代值。若要在多个步骤中累积标志,可自行 combine,或使用 decimal_checked,它同时保留最近一次的(raised)与累积的(flags)标志集合。
///|
test "flags report conditions beside a defined value" {
let ctx = @bin_float.BinaryContext::binary64()
let one = @bin_float.BinFloat::from_int(1)
let (pole, pole_flags) = one.div_ctx(
@bin_float.BinFloat::negative_zero(),
ctx,
)
inspect(pole, content="-inf")
inspect(pole_flags.division_by_zero(), content="true")
let (huge, huge_flags) = @bin_float.BinFloat::from_double(1.0e308).mul_ctx(
@bin_float.BinFloat::from_int(10),
ctx,
)
inspect(huge, content="inf")
inspect(huge_flags.overflow() && huge_flags.inexact(), content="true")
let inf = @bin_float.BinFloat::inf(@def.Positive)
let (undefined, invalid) = inf.sub_ctx(inf, ctx)
inspect(@def.is_nan(undefined), content="true")
inspect(invalid.invalid_operation(), content="true")
}
GDA 状态与陷阱
decimal_gda 遵循 General Decimal Arithmetic 模型。每个运算返回一个 GdaOutcome,其中包含已定义的结果、下一个上下文以及本次运算引发的标志。下一个上下文的 status() 是迄今为止所有引发条件的粘滞并集。当某个引发的条件在上下文的陷阱集合中已启用时,结果为 Trapped(signal, value, context, raised) 而非 Completed(value, context, raised);已定义的结果依然保留。若同时引发多个已启用的条件,被捕获的信号按以下优先级取第一个:invalid operation、division by zero、division undefined、division impossible、invalid context、conversion syntax、overflow、underflow、subnormal、inexact、rounded、clamped、lost digits。
///|
test "a GDA trap keeps the defined result" {
let ctx = @decimal_gda.GdaContext::decimal64().trap(
@decimal_gda.DivisionByZero,
)
let one = @decimal_gda.Decimal::from_string("1").unwrap()
let zero = @decimal_gda.Decimal::from_string("0").unwrap()
match @decimal_gda.divide(one, zero, ctx) {
Trapped(signal, value, next, _) => {
inspect(signal == @decimal_gda.DivisionByZero, content="true")
inspect(value, content="inf")
inspect(next.status().division_by_zero, content="true")
}
Completed(_, _, _) => fail("an enabled trap must fire")
}
}
checked 错误
ArithmeticError(由 def 重新导出)具有一个种类:DivisionByZero、ParseError、DomainError、FormatError、UnsupportedOperation、UnorderedComparison 或 CertificationFailure。它用于 checked 契约无值可返回的情形:div_checked 除以零、对负数求 sqrt、compare_checked 遇到 NaN、字面量格式错误。BinFloatResult 与 BallFloatResult 保留第一个错误并跳过其余步骤。
初等函数两种形式都有。若认证细化无法在预算内确定舍入,try_*_ctx 函数返回带有 CertificationFailure 详情的 Err。非 try 形式从不中止:二进制版本返回静默 NaN 并引发 invalid operation,十进制与 GDA 版本返回各自的无效结果,以便标志与陷阱照常生效。
包络
BallFloat 表示一个以二进制数为端点的闭实数集 ,或特殊集合 Empty()与 Entire()之一。函数 的区间扩展 必须满足包含性质
向外舍入保证了这一点:精确下端点用 舍入,精确上端点用 舍入,由 与 可知存储的区间包含精确区间。44 R. E. Moore、R. B. Kearfott 与 M. J. Cloud,Introduction to Interval Analysis,SIAM 2009,第 3 章;集合与装饰模型见 IEEE 1788-2015 第 10–11 条。 宽的包络也是正确结果;紧致性是质量指标,而非契约。除以包含零的区间可能返回 Entire。
BallFloatDecorated 增加了一个 IEEE 1788 装饰(decoration),描述 在 上的已知性质:Com(在有界 上有定义、连续且有界)、Dac(有定义且连续)、Def(有定义)、Trv(一无所知)以及 Ill(该区间为 NaI,即 “not an interval”)。NaI 不同于 Empty。装饰并非标量标志;BallFlags 报告的是 BallContext 的精度与范围事件。
///|
test "an enclosure contains every exact result" {
let one = @ball_float.BallFloat::from_int(1, precision=53)
let three = @ball_float.BallFloat::from_int(3, precision=53)
let third = one.div(three)
inspect(third.contains(@bin_float.BinFloat::from_double(1.0 / 3.0)), content="true")
let around_zero = @ball_float.BallFloat::from_bounds(
@bin_float.BinFloat::from_int(-1),
@bin_float.BinFloat::from_int(1),
)
inspect(one.div(around_zero).is_entire(), content="true")
let partly_defined = @ball_float.BallFloatDecorated::new(
@ball_float.BallFloat::from_bounds(
@bin_float.BinFloat::from_int(-1),
@bin_float.BinFloat::from_int(4),
),
)
inspect(partly_defined.decoration(), content="com")
inspect(partly_defined.sqrt_interval().decoration(), content="trv")
}
量子与同值类
对十进制值而言,运算返回同值类中的哪个成员是其契约的一部分。当精确结果在精度范围内可以容纳时,IEEE 754 与 GDA 选择具有理想指数的成员:55 IEEE 754-2019 第 5.2 条及表 5.1;Cowlishaw,General Decimal Arithmetic Specification 1.70,“Arithmetic operations”。
而当结果必须舍入时,选择能容纳的系数最大的成员。解析会保留字面量的量子。quantize(x, y) 将 舍入到 的量子;reduce_ctx(GDA reduce)与 normalized() 去除末尾的零。数值比较只看值;same_quantum 以及全序 compare_total(IEEE)与 compare_total(GDA)还会考虑同值类。
///|
test "decimal results keep the ideal exponent" {
let ctx = @decimal.DecimalContext::decimal64()
let a = @decimal.Decimal::from_string("1.20").unwrap()
let b = @decimal.Decimal::from_string("1.3").unwrap()
inspect(a.add_ctx(b, ctx).0, content="2.50")
inspect(a.mul_ctx(b, ctx).0, content="1.560")
let c = @decimal.Decimal::from_string("2.400").unwrap()
let d = @decimal.Decimal::from_string("1.2").unwrap()
inspect(c.div_ctx(d, ctx).0, content="2.00")
let (cents, flags) = @decimal.Decimal::from_string("2.345")
.unwrap()
.quantize(@decimal.Decimal::from_string("0.01").unwrap(), ctx)
inspect(cents, content="2.34")
inspect(flags.contains(@decimal.Inexact), content="true")
let x = @decimal.Decimal::from_string("12.30").unwrap()
let y = @decimal.Decimal::from_string("12.3").unwrap()
inspect(x.compare(y), content="0")
inspect(x.compare_total(y), content="-1")
}
带符号零与 NaN
零
零带有符号,从而 与 能够保留下溢的方向。规则遵循 IEEE 754-2019 第 6.3 条:
- 积或商的符号为操作数符号的异或;
- 符号相反的操作数之和若精确为零,或 ,其结果均为 ——除非舍入方向为 ,此时结果为 ;
- ,且舍入到整数时保留符号();
- 数值比较将 与 视为相等。
NaN
静默 NaN 在算术中悄无声息地传播;信号 NaN 在被运算使用时引发 invalid operation,并在结果中变为静默 NaN。NaN 带有符号和一个整数载荷(nan_payload);含 NaN 操作数的运算返回由其中第一个 NaN 派生的静默 NaN。
///|
test "zero and NaN rules" {
let ctx = @bin_float.BinaryContext::binary64()
let down = @bin_float.BinaryContext::binary64(rounding=RoundTowardNegative)
let one = @bin_float.BinFloat::from_int(1)
inspect(one.sub_ctx(one, ctx).0.is_negative_zero(), content="false")
inspect(one.sub_ctx(one, down).0.is_negative_zero(), content="true")
inspect(@bin_float.BinFloat::negative_zero().sqrt_ctx(ctx).0, content="-0")
let (quieted, flags) = @bin_float.BinFloat::signaling_nan().add_ctx(one, ctx)
inspect(quieted.is_quiet_nan(), content="true")
inspect(flags.invalid_operation(), content="true")
}
比较
IEEE 比较有四种结果:小于、等于、大于以及无序,后者在任一操作数为 NaN 时出现。不同的 API 提供不同的序,选对序非常重要:
| API | 序 | NaN | 与 |
|---|---|---|---|
compare_quiet, less_quiet, equal_quiet, … (bin_float) | IEEE 偏序,@def.PartialOrder | Unordered;仅对信号 NaN 引发 invalid | 相等 |
compare_signaling, less_signaling, … (bin_float) | IEEE 偏序 | Unordered;对任何 NaN 都引发 invalid | 相等 |
compare_checked | 数值序 | 带有 UnorderedComparison 的 Err | 相等 |
compare、<、<=、排序(Compare) | 全预序 | 所有 NaN 彼此相等,且大于所有数 | 相等 |
total_order、total_order_compare、total_order_mag(bin_float)、compare_total(decimal) | 作用于表示的 IEEE totalOrder | 按符号、种类和载荷排序 |
compare 将 NaN 排在所有数之上,使 Compare 成为全预序、排序永不失败;它从不中止。当必须把 NaN 视为无序时,请使用静默谓词或 compare_checked。
相等性取决于类型。Decimal 的 == 对有限值按数值比较(-0 == 0.00),并将两个 NaN 视为相等。BinFloat 与 BallFloat 派生了 Eq,因此它们的 == 比较的是表示,包括零的符号和精度:在这里 -0 == +0 为假,而 compare 返回 0。比较二进制值的数值相等性请使用 compare(...) == 0 或 equal_quiet。
///|
test "choosing a comparison" {
let nan = @bin_float.BinFloat::nan()
let one = @bin_float.BinFloat::from_int(1)
inspect(nan.compare(one), content="1")
inspect(nan > @bin_float.BinFloat::inf(@def.Positive), content="true")
inspect(nan.compare_checked(one) is Err(_), content="true")
let (order, flags) = nan.compare_quiet(one)
inspect(order == @def.Unordered, content="true")
inspect(flags.invalid_operation(), content="false")
let neg_zero = @bin_float.BinFloat::negative_zero()
let pos_zero = @bin_float.BinFloat::zero()
inspect(neg_zero.compare(pos_zero), content="0")
inspect(neg_zero.total_order_compare(pos_zero), content="-1")
inspect(neg_zero == pos_zero, content="false")
}
基数之间的转换
每个二进制小数都有有限的十进制展开,因为 ;而大多数十进制小数没有有限的二进制展开,因为 ,而 不是二进有理数。因此十进制到二进制的转换通常不精确,二进制到十进制的转换则是精确的,但可能需要很多数位。BinFloat::from_string_ctx(IEEE convertFromDecimalCharacter)与 to_decimal_string_ctx(convertToDecimalCharacter)对任意精度和指数都是正确舍入的;to_shortest_string 打印能读回同一值的最少数位,0.1 + 0.2 正是借此显示出其舍入误差。
交换格式转换的范围更窄:BinaryInterchange(binary16/32/64/128)以及 decimal32/64/128 的 DPD 与 BID 编码固定了字段宽度、指数界和特殊值编码。semantic 将各个包的值投影为精确有理数,因此能分辨十进制 与二进制 是不同的数;该投影有意丢弃精度、量子、带符号零、载荷、装饰和标志。
///|
test "decimal 0.1 is not binary 0.1" {
let sum = @bin_float.BinFloat::from_double(0.1).add(
@bin_float.BinFloat::from_double(0.2),
)
inspect(sum.to_shortest_string(), content="0.30000000000000004")
let decimal_tenth = @semantic.SemanticScalar::from_decimal(
@decimal.Decimal::from_string("0.1").unwrap(),
)
let binary_tenth = @semantic.SemanticScalar::from_bin_float(
@bin_float.BinFloat::from_double(0.1),
)
inspect(decimal_tenth == binary_tenth, content="false")
let decimal_half = @semantic.SemanticScalar::from_decimal(
@decimal.Decimal::from_string("0.500").unwrap(),
)
let binary_half = @semantic.SemanticScalar::from_bin_float(
@bin_float.BinFloat::from_double(0.5),
)
inspect(decimal_half == binary_half, content="true")
}
决策清单
选择 API 前应回答:
- 结果是标量值、表示,还是实数集合?
- 基数、精度、指数范围或量子是否必须保持可观察?
- 调用方需要逐运算的标志、GDA 的粘滞状态与陷阱,还是可短路的 checked 错误?
- 是否可能出现 NaN、无穷、带符号零、Empty、Entire 或 NaI?
- 数值序是否足够,还是需要 IEEE 偏序、全序或集合关系?
- 转换是任意精度的,还是固定的交换格式?
- 哪些固定版本的符合性证据支持该结论?参见验证。
Footnotes
-
IEEE 754-2019 第 4.3 条定义了 roundTiesToEven、roundTiesToAway、roundTowardPositive、roundTowardNegative 与 roundTowardZero。远离零舍入以及十进制的 “05up” 模式来自 General Decimal Arithmetic 规范(Cowlishaw)。 ↩
-
N. J. Higham,Accuracy and Stability of Numerical Algorithms,第 2 版,SIAM 2002,§2.2。含 的下溢形式即该书定理 2.3;Goldberg 的 “What every computer scientist should know about floating-point arithmetic”(ACM Computing Surveys 23(1),1991)对二进制情形给出了相同的推导。 ↩
-
IEEE 754-2019 第 7 条。默认异常处理返回此处列出的值并引发状态标志;
floating恰好实现这一默认行为,从不改变控制流。 ↩ -
R. E. Moore、R. B. Kearfott 与 M. J. Cloud,Introduction to Interval Analysis,SIAM 2009,第 3 章;集合与装饰模型见 IEEE 1788-2015 第 10–11 条。 ↩
-
IEEE 754-2019 第 5.2 条及表 5.1;Cowlishaw,General Decimal Arithmetic Specification 1.70,“Arithmetic operations”。 ↩