2次方程式
提供: floatingexception
2次方程式の解法
二次方程式の解法は、純粋数学的には高校二年で解決済みですが、 数値的には深い問題があります。
において、加減算で桁落ちが起きて、精度が出ないことがあります。 絶対値が大きいほうの解をとして、もう一つの解を
によって求めると、桁落ちが起きません。
数値例を示します。
の解は、明らかに1と0.0001ですが、 解の公式をそのまま使うと、次のように大きな誤差が発生します。 Fortranのコードで倍精度演算で求めました。
1.00000000000000000 9.99999999999889865E-0005
改良した方法では、精度が上がります。
1.00000000000000000 1.00000000000000004E-0004
富士通SSL2のDQRDR互換のプログラム例を示します。
! (C) 2007 ISHIKAWA Naota ! This is free software without warranty under new BSD license. ! subroutine dqrdr2(a0, a1, a2, zz, icon) implicit none real(8), intent(in) :: a0, a1, a2 complex(8), intent(out) :: zz(2) integer, intent(out) :: icon real(8) :: dd, x1, x2 if (a0 == 0.0d+0 .and. a1 == 0.0d+0) then icon = 30000 return else if (a0 == 0.0d+0) then icon = 10000 zz(1) = -a2 / a1 return endif dd = a1 * a1 - 4.0d+0 * a0 * a2 if (dd == 0.0d+0) then x1 = -a1 / (2.0d+0 * a0) zz(1) = x1 zz(2) = x1 else if (dd < 0.0d+0) then x1 = -a1 / (2.0d+0 * a0) x2 = sqrt(-dd) / (2.0d+0 * a0) zz(1) = cmplx(x1, x2) zz(2) = cmplx(x1, -x2) else if (0.0d+0 < a1) then x2 = (-a1 - sqrt(dd)) / (2.0d+0 * a0) zz(1) = a2 / (a0 * x2) zz(2) = x2 else x1 = (-a1 + sqrt(dd)) / (2.0d+0 * a0) zz(1) = x1 zz(2) = a2 / (a0 * x1) endif endif icon = 0 return endsubroutine dqrdr2