Lapack: dhseqrは間違った結果を出します

作成日 2018年07月05日  ·  2コメント  ·  ソース: Reference-LAPACK/lapack

このプログラム

program bug
    implicit none

    double precision :: H1(4, 4), H2(4, 4), wr1(4), wi1(4), wr2(4), wi2(4), Z, work(10), dble, epsilon
    integer*8 :: info

    H1(:,:) = 0

    H1(2, 1) = dble(z'bfdf916d32df0e1d')
    H1(3, 2) = dble(z'bf782807624514d9')
    H1(4, 3) = dble(z'bf80d94d89578784')
    H1(1, 2) = dble(z'3fdf916d32df0e1d')
    H1(2, 3) = dble(z'3f782807624514da')
    H1(3, 4) = dble(z'3f80d94d89578784')

    H2(:,:) = H1
    H2(4,4) = epsilon(H2(4,4))

    call dhseqr('E', 'N', 4_8, 1_8, 4_8, H1, 4_8, wr1, wi1, Z, 1_8, work, 10, info)
    call dhseqr('E', 'N', 4_8, 1_8, 4_8, H2, 4_8, wr2, wi2, Z, 1_8, work, 10, info)

    write(*,*) 'wr1: ', wr1
    write(*,*) 'wi1: ', wi1
    write(*,*) 'wr2: ', wr2
    write(*,*) 'wi2: ', wi2

end program bug

を生成します

 wr1:    0.0000000000000000        0.0000000000000000        0.0000000000000000        0.0000000000000000
 wi1:   0.73992959728054897      -0.73992959728054897        8.2263841908860064E-003  -8.2263841908860064E-003
 wr2:    0.0000000000000000        0.0000000000000000        1.1102230246251565E-016   1.1102230246251565E-016
 wi2:   0.49328639818703252      -0.49328639818703252        8.2263841908860116E-003  -8.2263841908860116E-003

LAPACK3.8を搭載した私のマシンで。

ここで条件付けの問題があるべきではないと思います。 収束基準は、ゼロ対角によって混乱する可能性があると思います。

High Bug

全てのコメント2件

私はこのバグにひびが入った。 よくわかりませんが、dlanv2のアンダーフロー/丸め誤差が原因のようです。

反復中に次のことが発生します。

  • シフトが純粋に虚数である場合、構造は保持されます
  • 対角要素と比較するため、デフレを得るにはH(3,2)がsfminの下にある必要があります
  • 10回の反復の後、アドホックシフト(純粋に想像上のものではありません)を使用して、デフレを取得します

最終的に、最初の2つの固有値に対して次のサブブロックが作成されます。

  0.0000E+00      4.9329E-01
 -4.9329E-01     -9.8813-324

DLANV2はこれを次のように変換します。

  0.0000E+00      7.3993E-01
 -7.3993E-01      0.0000E+00

原因は、DLANV2の218行目の丸め誤差です。CSはsqrt(0.5)であるため、SNもsqrt(0.5)である必要がありますが、代わりに-1になります。 2x2ブロックを正しく正規化するローテーションは言うまでもなく、有効なローテーションでさえありません。

実際、対角線のゼロ以外の小さな値は、計算を完全に台無しにしているようです

julia> eigvals([0.0 1.0; -1.0 0.0])
2-element Array{Complex{Float64},1}:
 0.0 - 1.0im
 0.0 + 1.0im

julia> eigvals([0.0 1.0; -1.0 nextfloat(0.0)])
2-element Array{Complex{Float64},1}:
 0.0 - 0.5000000000000001im
 0.0 + 0.5000000000000001im

julia> eigvals([0.0 1.0; -1.0 1e-310])
2-element Array{Complex{Float64},1}:
 0.0 - 1.000000000000023im
 0.0 + 1.000000000000023im
このページは役に立ちましたか?
0 / 5 - 0 評価