core 教程
本教程使用泛型 Complex[T] 类型进行复数运算。你将构造并打印复数,在 Double 和整数上用它们进行计算,编写通过 luna-generic trait 接受复数的泛型代码,并原地更新值。其背后的代数原理见核心设计。
快速开始
moon add Luna-Flow/luna-complex@0.2.0
import {
"Luna-Flow/luna-complex" @complex,
}
fn main {
let z = @complex.Complex::new(1.0, 2.0)
let w = @complex.Complex::new(3.0, -1.0)
println("z + w = \{z + w}")
println("z * w = \{z * w}")
println("z / w = \{z / w}")
}
z + w = 4 + 1i
z * w = 5 + 5i
z / w = 0.1 + 0.7000000000000001i
日常任务
共轭与模平方
是实数:
fn main {
let z = @complex.Complex::new(3.0, 4.0)
let n = z * z.conjugate()
println("z * conj(z) = \{n}")
println("1 / z = \{z.inv()}")
}
z * conj(z) = 25 + 0i
1 / z = 0.12 + -0.16i
高斯整数
在 Int 上,Complex[Int] 就是高斯整数环 。除法以外的一切都能工作,且结果是精确的:
fn main {
let a = @complex.Complex::new(2, 1)
let b = @complex.Complex::new(2, -1)
println("(2 + i)(2 - i) = \{a * b}")
let mut p = @complex.Complex::one()
for _ in 0..<4 {
p = p * @complex.Complex::new(1, 1)
}
println("(1 + i)^4 = \{p}")
}
(2 + i)(2 - i) = 5 + 0i
(1 + i)^4 = -4 + 0i
表明 在 中不是素数。
环上的泛型代码
针对 luna-generic trait 编写的代码可以接受复数。下面用 Horner 方法求 的值:
fn[T : @lg.Ring] horner(coefficients : Array[T], x : T) -> T {
let mut acc : T = @lg.Zero::zero()
for i = coefficients.length() - 1; i >= 0; i = i - 1 {
acc = acc * x + coefficients[i]
}
acc
}
fn main {
let one : @complex.Complex[Double] = @complex.Complex::one()
let zero : @complex.Complex[Double] = @complex.Complex::zero()
let i = @complex.Complex::new(0.0, 1.0)
println("p(i) = \{horner([one, zero, one], i)}")
println("p(2) = \{horner([1.0, 0.0, 1.0], 2.0)}")
}
p(i) = 0 + 0i
p(2) = 5
原地更新
set、set_re 和 set_im 会覆盖一个值。所有绑定到它的变量都会看到这一变化:
fn main {
let acc = @complex.Complex::new(0.0, 0.0)
let shared = acc
for k in 1..=3 {
let kd = k.to_double()
acc.set(acc.re + kd, acc.im - kd)
}
println("acc = \{acc}")
println("shared = \{shared}")
}
acc = 6 + -6i
shared = 6 + -6i
进阶
嵌套复数
Complex[T] 适用于任何具备所需 trait 的 T,包括 Complex[Double] 本身:
fn main {
let a = @complex.Complex::new(1.0, 2.0)
let b = @complex.Complex::new(-0.5, 0.25)
let z = @complex.Complex::new(a, b)
let w = z * z.inv()
println("z * z^-1 = (\{w.re}) + (\{w.im})j")
}
z * z^-1 = (1.0000000000000002 + 5.204170427930421e-17i) + (0 + 0i)j
乘积在舍入误差范围内等于 ,因为这个 的模平方 可逆。一般而言,Complex[Complex[Double]] 不是域;参见下面的常见陷阱。
解析函数
核心中没有 sqrt、exp 或 sin。对于 Complex[Double],请导入 Luna-Flow/luna-complex/float_backend;float_backend 教程介绍了用法。
常见陷阱
- 除以零会中止。
z / w和w.inv()对 调用Inverse::inv;对于Double,当该值为零时会中止,当 导致下溢时也是如此。稳健的除法请使用float_backend中的@fb.div。 - 大数值在除法中上溢。 当 时 上溢。
- 共享的修改。
let shared = z不会复制;setter 会改变每一个别名。 - 文本形式。 负虚部打印为
+ -2i;需要其他形式时,请使用debug_inspect或自行格式化。 - 嵌套类型不是域。 在
Complex[Complex[Double]]中, 这样的值模平方为零,inv会中止。
后续步骤
- 核心 API 列出了所有方法与实例。
- 核心设计推导了该构造以及成为域的条件。
- float_backend 教程介绍解析函数。
- luna-generic 记录了泛型代码中使用的 trait。