core API

ルートパッケージ Luna-Flow/luna-complex は、任意のスカラー型 T 上の複素数 a+bia + bi である Complex[T] を定義し、構築、インプレースでの変更、共役、算術演算子、luna-generic の代数構造トレイトを提供します。解析関数は含まず、それらは float_backend にあります。各インスタンスの背後にある代数は core の設計 で説明しています。

ソース: src/complex.mbt、src/complex_traits.mbt、src/extends.mbt。

インポート

import {
  "Luna-Flow/luna-complex" @complex,
}

例ではエイリアス @complex を使います。

型

Complex

実部 re と虚部 im を持つ複素数です。

pub(all) struct Complex[T] {
  mut re : T
  mut im : T
} derive(Eq, @debug.Debug)

値は i2=−1i^2 = -1 のもとでの re+im i\texttt{re} + \texttt{im}\,i です。両フィールドとも公開かつ可変で、構造体は pub(all) なので、パッケージ外のコードからも読み書きでき、レコードリテラルで構築できます。Complex[T] は参照型であり、同じ値への 2 つの束縛は互いの更新を観測します。

derive(Eq) は両方の部分を T の等価性で比較します(Double では 0.0 == -0.0 であり、NaN は自分自身と等しくありません)。derive(Debug) はレコード形式 { re: …, im: … } を出力します。

構築と変更

Complex::new

re+im ire + im\,i を構築します。

pub fn[T] Complex::new(T, T) -> Complex[T]

Complex::set

両方の部分をインプレースで上書きします。

pub fn[T] Complex::set(Complex[T], T, T) -> Unit

Complex::set_re

実部をインプレースで上書きします。

pub fn[T] Complex::set_re(Complex[T], T) -> Unit

Complex::set_im

虚部をインプレースで上書きします。

pub fn[T] Complex::set_im(Complex[T], T) -> Unit
test "construct and mutate" {
  let z = @complex.Complex::new(1.0, 2.0)
  assert_eq(z.re, 1.0)
  z.set(3.0, 4.0)
  z.set_im(-1.0)
  assert_eq(z, @complex.Complex::new(3.0, -1.0))
}

単位元

Complex::zero

0+0i0 + 0i を返します。

pub fn[T : @luna-generic.Zero] Complex::zero() -> Complex[T]

Complex::one

1+0i1 + 0i を返します。

pub fn[T : @luna-generic.One + @luna-generic.Zero] Complex::one() -> Complex[T]

どちらも Zero および One インスタンスから昇格されたメソッドです。

算術

各演算は演算子としても、昇格されたメソッドとしても利用できます。

項目演算子結果T への制約
Complex::addz + w(a+c)+(b+d)i(a + c) + (b + d)iAdd
Complex::subz - w(a−c)+(b−d)i(a - c) + (b - d)iSub
Complex::neg-z−a−bi-a - biNeg
Complex::mulz * w(ac−bd)+(ad+bc)i(ac - bd) + (ad + bc)iMul + Add + Sub
Complex::divz / w(ac+bd)+(bc−ad)ic2+d2\dfrac{(ac + bd) + (bc - ad)i}{c^2 + d^2}Field

ここで z=a+biz = a + bi、w=c+diw = c + di とします。

Complex::add

成分ごとに加算します。

pub fn[T : Add] Complex::add(Complex[T], Complex[T]) -> Complex[T]
pub impl[T : Add] Add for Complex[T]

Complex::sub

成分ごとに減算します。

pub fn[T : Sub] Complex::sub(Complex[T], Complex[T]) -> Complex[T]
pub impl[T : Sub] Sub for Complex[T]

Complex::neg

両方の部分の符号を反転します。

pub fn[T : Neg] Complex::neg(Complex[T]) -> Complex[T]
pub impl[T : Neg] Neg for Complex[T]

Complex::mul

i2=−1i^2 = -1 を用いて、4 回の乗算で乗算します。

pub fn[T : Mul + Add + Sub] Complex::mul(Complex[T], Complex[T]) -> Complex[T]
pub impl[T : Mul + Add + Sub] Mul for Complex[T]

Complex::div

絶対値の 2 乗の逆数を掛けることで除算します。

pub fn[T : @luna-generic.Field] Complex::div(Complex[T], Complex[T]) -> Complex[T]
pub impl[T : @luna-generic.Field] Div for Complex[T]

n=c2+d2n = c^2 + d^2 を計算し、次に Inverse::inv(n) を求め、zwˉz\bar w の両方の部分にそれを掛けます。この式はスケーリングされていません。Double では ∣w∣≳10154|w| \gtrsim 10^{154} で c2+d2c^2 + d^2 がオーバーフローし、∣w∣≲10−162|w| \lesssim 10^{-162} でアンダーフローします。また Double の Inverse::inv は、nn がゼロのとき(アンダーフローの結果ゼロになった場合を含む)Double::inv: division by zero で中断します。堅牢な浮動小数点除算には @fb.div を使ってください。

test "complex arithmetic" {
  let z = @complex.Complex::new(1.0, 2.0)
  let w = @complex.Complex::new(3.0, -1.0)
  assert_eq(z + w, @complex.Complex::new(4.0, 1.0))
  assert_eq(z - w, @complex.Complex::new(-2.0, 3.0))
  assert_eq(z * w, @complex.Complex::new(5.0, 5.0))
  assert_eq(z * w / w, z)
  assert_eq(-z, @complex.Complex::new(-1.0, -2.0))
}

共役と逆数

Complex::conjugate

zˉ=a−bi\bar z = a - bi を返します。

pub fn[T : Neg] Complex::conjugate(Complex[T]) -> Complex[T]
pub impl[T : Neg] @luna-generic.Conjugate for Complex[T]

Complex::inv

z−1=zˉ/(a2+b2)z^{-1} = \bar z / (a^2 + b^2) を返します。

pub fn[T : @luna-generic.Field] Complex::inv(Complex[T]) -> Complex[T]
pub impl[T : @luna-generic.Field] @luna-generic.Inverse for Complex[T]

Complex::div と同じくスケーリングされていない式を使い、絶対値がゼロのときに同じく中断します。

test "conjugate and inverse" {
  let z = @complex.Complex::new(3.0, 4.0)
  assert_eq(z.conjugate(), @complex.Complex::new(3.0, -4.0))
  assert_eq(z * z.conjugate(), @complex.Complex::new(25.0, 0.0))
  assert_eq(z.inv(), @complex.Complex::new(0.12, -0.16))
}

等価性とテキスト

Complex::equal

両方の部分を比較します。derive された Eq から昇格されたメソッドです。== を使うことを推奨します。

pub fn[T : Eq] Complex::equal(Complex[T], Complex[T]) -> Bool

Complex::to_string

T の Show を使って zz を "<re> + <im>i" の形式に整形します。

pub fn[T : Show] Complex::to_string(Complex[T]) -> String
pub impl[T : Show] Show for Complex[T]

虚部の符号は T が出力するため、1−2i1 - 2i は 1 + -2i と出力されます。文字列補間 "\{z}" も同じテキストを使います。

test "text form" {
  inspect(@complex.Complex::new(1.5, -2.0), content="1.5 + -2i")
  debug_inspect(@complex.Complex::new(1, 2), content="{ re: 1, im: 2 }")
}

構造インスタンス

Complex[T] は以下の制約のもとで luna-generic の代数構造トレイトを実装します。各法則の導出は core の設計 にあります。

インスタンスT への制約
ZeroZero
OneOne + Zero
AddMonoidAdd + Zero
AddGroupAdd + Zero + Neg + Sub
MulMonoidRing
SemiringRing
RingRing
InverseField
MulGroupField
FieldField
ConjugateNeg
fn[T : @lg.Field] average(a : T, b : T) -> T {
  let two = @lg.One::one() + @lg.One::one()
  (a + b) / two
}

test "generic field code accepts complex numbers" {
  let m = average(@complex.Complex::new(1.0, 2.0), @complex.Complex::new(3.0, 0.0))
  assert_eq(m, @complex.Complex::new(2.0, 1.0))
}

非推奨

これらのメソッド形式はトレイトインスタンスに由来し、インターフェースファイルからは隠されています。パッケージ外で使うと警告が出ます。

非推奨のメソッド代替
z.not_equal(w)z != w
z.output(logger)z.to_string() または "\{z}"
z.to_repr()Repr(z) または @debug.Debug::to_repr(z)