core 设计
本页推导 Complex[T] 的代数结构,说明每个 luna-generic 实例在何时合法,并解释泛型类型背后的设计选择:可变字段、未缩放的除法公式,以及与浮点分析的分离。
设计目标
为生态中的每种标量提供同一个泛型复数类型,其实例所声明的代数结构恰好是该构造所具有的结构,而 IEEE 特殊值、分支切割线和超越函数则交给后端包处理。
数学背景
构造
对于交换环 R R R ,R R R 上的复数是多项式环对由 x 2 + 1 x^2 + 1 x 2 + 1 生成的理想所作的商:
R [ i ] = R [ x ] / ( x 2 + 1 ) , i = x + ( x 2 + 1 ) , i 2 = − 1. R[i] = R[x]/(x^2 + 1), \qquad i = x + (x^2 + 1), \qquad i^2 = -1 . R [ i ] = R [ x ] / ( x 2 + 1 ) , i = x + ( x 2 + 1 ) , i 2 = − 1.
用首一多项式 x 2 + 1 x^2 + 1 x 2 + 1 做除法会留下唯一一个次数低于二的余式,因此每个元素都可唯一地写成 a + b i a + bi a + bi (a , b ∈ R a, b \in R a , b ∈ R ):即二元组 (re, im)。用多项式计算并以 i 2 = − 1 i^2 = -1 i 2 = − 1 化简,便得到本包的各项运算:
( a + b i ) ± ( c + d i ) = ( a ± c ) + ( b ± d ) i , ( a + b i ) ( c + d i ) = a c + ( a d + b c ) i + b d i 2 = ( a c − b d ) + ( a d + b c ) i . \begin{aligned}
(a + bi) \pm (c + di) &= (a \pm c) + (b \pm d)i, \\
(a + bi)(c + di) &= ac + (ad + bc)i + bd\,i^2 = (ac - bd) + (ad + bc)i .
\end{aligned} ( a + bi ) ± ( c + d i ) ( a + bi ) ( c + d i ) = ( a ± c ) + ( b ± d ) i , = a c + ( a d + b c ) i + b d i 2 = ( a c − b d ) + ( a d + b c ) i .
作为交换环的商,R [ i ] R[i] R [ i ] 是交换环,零元为 0 + 0 i 0 + 0i 0 + 0 i ,单位元为 1 + 0 i 1 + 0i 1 + 0 i ;R R R 通过 a ↦ a + 0 i a \mapsto a + 0i a ↦ a + 0 i 嵌入其中。
共轭与范数
a + b i ‾ = a − b i \overline{a + bi} = a - bi a + bi = a − bi 是由 x ↦ − x x \mapsto -x x ↦ − x 诱导的映射,它保持理想 ( x 2 + 1 ) (x^2 + 1) ( x 2 + 1 ) 不变,因此是一个二阶环自同构:
z + w ‾ = z ˉ + w ˉ , z w ‾ = z ˉ w ˉ , z ˉ ˉ = z . \overline{z + w} = \bar z + \bar w, \qquad \overline{zw} = \bar z\,\bar w,
\qquad \bar{\bar z} = z . z + w = z ˉ + w ˉ , z w = z ˉ w ˉ , z ˉ ˉ = z .
范数 N ( z ) = z z ˉ = ( a + b i ) ( a − b i ) = a 2 + b 2 N(z) = z\bar z = (a + bi)(a - bi) = a^2 + b^2 N ( z ) = z z ˉ = ( a + bi ) ( a − bi ) = a 2 + b 2 属于 R R R ,并且是乘性的:N ( z w ) = z w z ˉ w ˉ = N ( z ) N ( w ) N(zw) = zw\,\bar z\bar w = N(z)N(w) N ( z w ) = z w z ˉ w ˉ = N ( z ) N ( w ) 。
逆元与除法
若 N ( z ) N(z) N ( z ) 在 R R R 中可逆,则 z ⋅ z ˉ N ( z ) − 1 = 1 z \cdot \bar z\,N(z)^{-1} = 1 z ⋅ z ˉ N ( z ) − 1 = 1 ,因此
z − 1 = z ˉ N ( z ) = a a 2 + b 2 − b a 2 + b 2 i , a + b i c + d i = ( a c + b d ) + ( b c − a d ) i c 2 + d 2 . z^{-1} = \frac{\bar z}{N(z)} = \frac{a}{a^2 + b^2} - \frac{b}{a^2 + b^2}\,i,
\qquad
\frac{a + bi}{c + di} = \frac{(ac + bd) + (bc - ad)i}{c^2 + d^2} . z − 1 = N ( z ) z ˉ = a 2 + b 2 a − a 2 + b 2 b i , c + d i a + bi = c 2 + d 2 ( a c + b d ) + ( b c − a d ) i .
反之,若 z z z 可逆,则 N ( z ) N ( z − 1 ) = N ( 1 ) = 1 N(z)N(z^{-1}) = N(1) = 1 N ( z ) N ( z − 1 ) = N ( 1 ) = 1 ,因此 N ( z ) N(z) N ( z ) 可逆。所以 z z z 是单位当且仅当 a 2 + b 2 a^2 + b^2 a 2 + b 2 是单位。
何时该构造是域
设 K K K 为域。K [ x ] / ( x 2 + 1 ) K[x]/(x^2 + 1) K [ x ] / ( x 2 + 1 ) 是域当且仅当 x 2 + 1 x^2 + 1 x 2 + 1 在 K K K 上不可约,即 − 1 -1 − 1 在 K K K 中不是平方数。直接来看:满足 N ( z ) = a 2 + b 2 = 0 N(z) = a^2 + b^2 = 0 N ( z ) = a 2 + b 2 = 0 的非零 z z z 必有 b ≠ 0 b \ne 0 b = 0 ,从而 ( a / b ) 2 = − 1 (a/b)^2 = -1 ( a / b ) 2 = − 1 。反之,若 s 2 = − 1 s^2 = -1 s 2 = − 1 ,则 ( s + i ) ( s − i ) = s 2 + 1 = 0 (s + i)(s - i) = s^2 + 1 = 0 ( s + i ) ( s − i ) = s 2 + 1 = 0 给出了零因子。
对于 K = R K = \mathbb R K = R (Float、Double),− 1 -1 − 1 不是平方数,R [ i ] = C \mathbb R[i] = \mathbb C R [ i ] = C 是域。
对于 K = C K = \mathbb C K = C (Complex[Double]),− 1 = i 2 -1 = i^2 − 1 = i 2 是平方数,因此 Complex[Complex[Double]] ≅ C [ j ] / ( j 2 + 1 ) ≅ C × C \cong \mathbb C[j]/(j^2 + 1) \cong \mathbb C \times \mathbb C ≅ C [ j ] / ( j 2 + 1 ) ≅ C × C 是一个含零因子的环,例如 ( 1 + i j ) ( 1 − i j ) = 1 − i 2 j 2 = 0 (1 + ij)(1 - ij) = 1 - i^2 j^2 = 0 ( 1 + ij ) ( 1 − ij ) = 1 − i 2 j 2 = 0 。
设计决策
实例跟随 T 的结构
问题。 Complex[T] 可以实现哪些 luna-generic trait?
选择。 Zero、One、AddMonoid 和 AddGroup 只需要 T 的相应运算,因为它们逐分量作用。MulMonoid、Semiring 和 Ring 需要 T : Ring,因为乘积要用到减法(a c − b d ac - bd a c − b d ),而 R [ i ] R[i] R [ i ] 的环公理依赖于 R R R 的环公理。Inverse、MulGroup、Field 以及 Div 运算符需要 T : Field 来计算 N ( z ) − 1 N(z)^{-1} N ( z ) − 1 。Conjugate 只需要 Neg。
Field 实例对每个 T : Field 都有声明。由上一节可知,当 − 1 -1 − 1 在 T 中不是平方数时它是合法的,这涵盖了实数标量类型;对于 T = Complex[Double] 则不然,inv 会在非零的零因子上中止。trait 约束无法表达“−1 不是平方数”,因此该实例在这里信任调用者。1 1 这是 Luna Flow“只实现合法实例”这一规则中的一个已知缺口。测试套件只在范数可逆的值上使用嵌套复数。
四次乘法
备选方案。 使用四次乘法的教科书式乘积 ( a c − b d ) + ( a d + b c ) i (ac - bd) + (ad + bc)i ( a c − b d ) + ( a d + b c ) i ;高斯的三次乘法形式 k 1 = c ( a + b ) k_1 = c(a + b) k 1 = c ( a + b ) 、k 2 = a ( d − c ) k_2 = a(d - c) k 2 = a ( d − c ) 、k 3 = b ( c + d ) k_3 = b(c + d) k 3 = b ( c + d ) ,乘积为 ( k 1 − k 3 ) + ( k 1 + k 2 ) i (k_1 - k_3) + (k_1 + k_2)i ( k 1 − k 3 ) + ( k 1 + k 2 ) i 。
选择。 四次乘法。在浮点下,教科书形式的按范数相对误差至多为 5 u \sqrt5\,u 5 u ,2 2 R. Brent, C. Percival and P. Zimmermann, “Error bounds on complex floating-point multiplication”, Mathematics of Computation 76 (2007). 而三次乘法形式引入了 a + b a + b a + b 、d − c d - c d − c 这类容易相消的和,按分量的精度更差;并且对于泛型 T,乘法不一定比加法更昂贵。
按分量看,f l ( a c − b d ) = a c ( 1 + θ 2 ) − b d ( 1 + θ 2 ′ ) \mathrm{fl}(ac - bd) = ac(1 + \theta_2) - bd(1 + \theta_2') fl ( a c − b d ) = a c ( 1 + θ 2 ) − b d ( 1 + θ 2 ′ ) ,其中 ∣ θ 2 ∣ ≤ γ 2 = 2 u / ( 1 − 2 u ) |\theta_2| \le \gamma_2 = 2u/(1 - 2u) ∣ θ 2 ∣ ≤ γ 2 = 2 u / ( 1 − 2 u ) ,因此
∣ f l ( a c − b d ) − ( a c − b d ) ∣ ≤ γ 2 ( ∣ a c ∣ + ∣ b d ∣ ) , |\mathrm{fl}(ac - bd) - (ac - bd)| \le \gamma_2\,(|ac| + |bd|), ∣ fl ( a c − b d ) − ( a c − b d ) ∣ ≤ γ 2 ( ∣ a c ∣ + ∣ b d ∣ ) ,
除非 a c ac a c 与 b d bd b d 相消,否则它相对于结果是很小的。
泛型核心中的教科书式除法
问题。 除法需要 N ( w ) − 1 N(w)^{-1} N ( w ) − 1 ;对浮点数而言,c 2 + d 2 c^2 + d^2 c 2 + d 2 远在 c + d i c + di c + d i 之前就会上溢或下溢。
备选方案。 带缩放的算法(Smith 算法,或按 2 的幂重新缩放)需要比较和绝对值,而泛型域不具备这些;教科书公式只需要域运算。
选择。 泛型的 Div 和 Inverse 使用教科书公式,配合 T 的 Inverse::inv。对于精确的域它是精确的。对于 Double,只要 c 2 + d 2 c^2 + d^2 c 2 + d 2 不超出范围它就是正确的,而 Double 的 Inverse 在遇到零(包括下溢后的范数)时中止。带缩放且考虑特殊值的除法位于 float_backend 。
可变字段
问题。 复数值常常在循环中更新(累加器、递推),每一步都分配新值是一种浪费。
选择。 Complex[T] 是一个 pub(all) 结构体,带有 mut re 和 mut im,以及 set、set_re 和 set_im。每个运算都返回新值,从不修改其输入,因此不调用这些 setter 的代码可以把复数当作值来对待。确实要修改的调用者必须记住该结构体是按引用共享的。
核心中没有解析函数
z \sqrt z z 、log z \log z log z 或 sin z \sin z sin z 需要序、绝对值、实数标量的超越函数、分支的选择以及 IEEE 特殊值。这些对泛型域都不存在。因此根包止步于代数,由 float_backend 包为 Double 提供分析功能。
文本与调试形式
Show 使用 T 的文本打印 re + imi(1 − 2 i 1 - 2i 1 − 2 i 打印为 1 + -2i),这是该类型的规范文本,也是 to_string 保留为提升方法的原因。Debug 为测试和诊断打印记录形式。MoonBit 0.10 中其他 trait 方法的提升在 src/extends.mbt 中显式完成。
正确性与不变量
对于 T : Ring,由于 R [ i ] R[i] R [ i ] 是商环,环公理成立;测试套件在整数上检查结合律、单位元以及 z w ‾ = z ˉ w ˉ \overline{zw} = \bar z\bar w z w = z ˉ w ˉ 。
对于精确的 T,z * z.conjugate() 精确等于 N ( z ) + 0 i N(z) + 0i N ( z ) + 0 i 。
当 N ( w ) N(w) N ( w ) 、N ( z ) N(z) N ( z ) 为单位时,z * w / w == z 与 z.inv() * z == 1 对精确的域成立;对 Double 在范围内则在舍入误差意义下成立。
没有任何运算会修改其参数;只有三个 setter 会。
被否决的方案
仅支持 Double 的复数类型。 这会导致为 Float、整数(高斯整数)和精确有理数重复定义该类型。
不可变字段。 值语义更清晰,但对原地更新 re 和 im 的现有调用者来说是破坏性变更。
在核心中做带缩放的除法。 它需要泛型域所缺乏的序和量级运算。
边界
不提供解析函数或超越函数,不做特殊值处理,没有分支切割线;参见 float_backend 。
核心中没有极坐标表示。
不检查 T 是否使 R [ i ] R[i] R [ i ] 成为域;Field 实例信任这一点。
不为浮点 T 提供防上溢的除法。