checked 设计

本页解释对偶数的哪些运算具有带检查的形式、它们的错误如何从求导规则中产生,以及为什么门面包复用 arithmetic 的错误模型。

设计目标

让被求导的代码以值的形式报告非法运算,使用与 Luna Flow 标量代码相同的错误类型,并使带检查的运算不可能返回一个有效的值却附带无效的导数。

数学背景

导数在何处失效

当 f(a+bε)=f(a)+f′(a) b εf(a + b\varepsilon) = f(a) + f'(a)\,b\,\varepsilon 的任一分量无定义时,带检查的运算必须失败。对于这两个带检查的运算:

a+bεc+dε=ac+bc−adc2 εneeds c≠0,a+bε=a+b2a εneeds a>0.\begin{aligned} \frac{a + b\varepsilon}{c + d\varepsilon} &= \frac{a}{c} + \frac{bc - ad}{c^2}\,\varepsilon &&\text{needs } c \ne 0, \\ \sqrt{a + b\varepsilon} &= \sqrt a + \frac{b}{2\sqrt a}\,\varepsilon &&\text{needs } a > 0 . \end{aligned}

商恰好在值失效的地方失效,因为在精确算术中 c2≠0  ⟺  c≠0c^2 \ne 0 \iff c \ne 0。平方根则不同:a\sqrt a 在 a=0a = 0 处存在,但 ⋅\sqrt{\cdot} 在那里不可导(其差商 h/h=h−1/2\sqrt h / h = h^{-1/2} 无界),因此对偶运算的定义域是开半直线 a>0a > 0,比标量平方根的定义域 a≥0a \ge 0 更小。

浮点数的定义域

在 Double 中,非零的 cc 也可能使 c2c^2 为零:当 ∣c∣<2−537|c| < 2^{-537} 时(采用就近舍入并支持渐进下溢),c2c^2 会下溢为 00,即使 a/ca/c 可能是有限值。这时带检查的商会因切向分量而报告除以零。这类输入最好先重新缩放;dual 设计 假定不发生下溢。

设计决策

检查两个分量

问题。 带检查的标量运算可能成功,而导数却不存在。

选择。 每个带检查的对偶运算都对值调用带检查的标量运算,对切向分量的除法调用 div_checked,并返回遇到的第一个错误。这使得对偶运算的定义域成为 ff 与 f′f' 定义域的交集,正如上面推导的那样;特别地,sqrt_checked 在 00 处失败。

不对零切向分量做特殊处理

当 a=0a = 0 且 b=0b = 0 时,切向分量是不定式 0/00/0。可以返回 00(常数输入没有需要报告的导数),但那样会让结果取决于常数是如何产生的。实现交由 T 决定,对于 Double,这是一个定义域错误。

复用 arithmetic

Dual[T] 实现了 arithmetic 中的 DivChecked 和 SqrtChecked,本门面包恰好重新导出这两个 trait,以及 ArithmeticContext、ArithmeticError、ArithmeticErrorKind 和 RoundingMode。因此泛型的带检查代码无需改动即可在 Double 和 Dual[Double] 上运行,两个层次的错误也是同一类型。

只有除法和平方根

arithmetic 为除法、平方根、比较、解析和整数幂定义了带检查的 trait。其中只有除法和平方根是本仓库中具有求导规则的 T[ε]T[\varepsilon] 运算,因此只有它们具有带检查的对偶形式。对数和三角函数沿用 T 不带检查的语义。

正确性与不变量

  • div_checked(x, y) 恰好在 T 的 div_checked 对 a/ca/c 和 (bc−ad)/c2(bc - ad)/c^2 都成功时成功;此时它等于用相同运算计算出的 x / y。
  • sqrt_checked(x) 恰好在 T 的 sqrt_checked(a) 和 div_checked(b, 2√a) 都成功时成功;对于 Double,即 a>0a > 0 或 aa 为 NaN。
  • 上下文被原样传给 T,且从不被修改。

被否决的方案

  • 专门的 autodiff 错误类型。 它会与 ArithmeticError 重复,并迫使每个边界处都进行转换。
  • Option 结果。 它会丢失失败的原因。
  • 只检查值。 这会让”带检查的”运算返回无穷大或 NaN 的导数。

边界

  • 没有带检查的对数、指数或三角运算。
  • 没有上下文相关(ArithmeticOutcome)的运算,也没有舍入诊断。
  • 不会自动重新缩放极小的除数。