三次方程式を解く¶
カルダノの方法では、まずモニックな三次方程式を変数変換し、二次項のない 次の形にします。
$$ y^3+py+q=0. $$
$y=(s_1+s_2)/3$ とおくと、$s_1^3$ と $s_2^3$ は次の二次方程式の解になります。
$$ t^2+27qt-27p^3=0. $$
三つの解は、1の3乗根 $\omega=(-1+i\sqrt3)/2$ を使って得られます。
Egisonによるカルダノの構成¶
最初のmatch節は、二次項のない三次方程式を扱います。第2の節は変数変換 $x=y-b/3$ を行い、最後の節は最高次係数で割ります。小さな型付き二次方程式 ソルバーも定義することで、このノートブックだけで計算を完結させています。
declare symbol x, a, b, c, d, p, q: MathValue
def quadraticRoots
(a : MathValue)
(b : MathValue)
(c : MathValue)
: (MathValue, MathValue) :=
( ((- b) + sqrt (b ^ 2 - 4 * a * c)) / (2 * a)
, ((- b) - sqrt (b ^ 2 - 4 * a * c)) / (2 * a) )
def omega : MathValue := ((-1) + i * sqrt 3) / 2
def cubicFormula : MathValue -> MathValue -> (MathValue, MathValue, MathValue) := cF
def cF (f : MathValue) (x : MathValue) : (MathValue, MathValue, MathValue) :=
match coefficients f x as list mathValue with
| [$a_0, $a_1, $a_2, $a_3] -> cF' a_3 a_2 a_1 a_0
def cF'
(a : MathValue)
(b : MathValue)
(c : MathValue)
(d : MathValue)
: (MathValue, MathValue, MathValue) :=
match (a, b, c, d) as (mathValue, mathValue, mathValue, mathValue) with
| (#1, #0, $p, $q) ->
let (s1, s2) := (2)#(rt 3 $1, rt 3 $2)
(quadraticRoots 1 (27 * q) ((-27) * p ^ 3))
in ( (s1 + s2) / 3
, (omega ^ 2 * s1 + omega * s2) / 3
, (omega * s1 + omega ^ 2 * s2) / 3 )
| (#1, _, _, _) ->
(3)#($1 - b / 3, $2 - b / 3, $3 - b / 3)
(withSymbols [x, y]
cF
(substitute
[(x, y - b / 3)]
(x ^ 3 + b * x ^ 2 + c * x + d))
y)
| (_, _, _, _) -> cF' 1 (b / a) (c / a) (d / a)
二次項のない三次方程式¶
$p$ と $q$ を記号のまま保つと、カルダノの公式に現れる冪根が出力にそのまま 現れます。タプルの三つの成分は、$\omega$ の冪だけが異なります。
cF (x ^ 3 + p * x + q) x
変数変換を実際に試す¶
次の多項式は、解があらかじめ分かるよう因数分解した形で記述します。Egisonは それを展開し、係数を取り出し、二次項を消去してから、三つの解をすべて 再構成します。
cF ((x - 1) * (x - 2) * (x - 3)) x
一般の最高次係数¶
同じ関数で、すべての係数が記号である非モニック三次式 $ax^3+bx^2+cx+d$ も扱えます。最初に $a$ で割って正規化します。
cF (a * x ^ 3 + b * x ^ 2 + c * x + d) x
まとめ¶
係数のパターン、代入、解の置換を直接操作できると、カルダノの公式を短い実行可能な 導出として表せます。三つの代数的な分岐は汎用ソルバーの内部に隠れず、明示された ままです。