64 ビット システムでは、numpy.float128dtype があります。( float9632 ビット システムにも dtype があると思います) numpy.linalg.eig128 ビットの float をサポートしていませんが、scipy.linalg.eig(一種の) サポートしています。
ただし、長期的には、これは重要ではありません。固有値問題の一般的なソルバーは、正確ではなく反復的であるため、余分な精度を維持しても何も得られません! np.linalg.eigどの形状でも機能しますが、正確な解を返すことはありません。
常に 2x2 行列を解いている場合、より正確な独自のソルバーを作成するのは簡単です。最後にこれの例を示します...
いずれにせよ、無意味に正確なメモリ コンテナーを構築する:
import numpy as np
import scipy as sp
import scipy.linalg
a = np.array([[-800.21,-600.00],[-600.00,-1000.48]], dtype=np.float128)
ex = np.exp(a)
print ex
eigvals, eigvecs = sp.linalg.eig(ex)
# And to test...
check1 = ex.dot(eigvecs[:,0])
check2 = eigvals[0] * eigvecs[:,0]
print 'Checking accuracy..'
print check1, check2
print (check1 - check2).dot(check1 - check2), '<-- Should be zero'
ただし、得られるものは を実行した場合と同じであることに気付くでしょうnp.linalg.eig(ex.astype(np.float64)。実際、私はそれscipyがやっていることだとかなり確信してnumpyいますが、静かに行うのではなく、エラーを発生させます。私はかなり間違っているかもしれませんが...
scipy を使用したくない場合の回避策の 1 つは、べき乗の後、固有値を解く前に再スケーリングし、それらを「通常の」浮動小数点としてキャストし、固有値を解決してから、後で float128 として再キャストし、再スケーリングすることです。
例えば
import numpy as np
a = np.array([[-800.21,-600.00],[-600.00,-1000.48]], dtype=np.float128)
ex = np.exp(a)
factor = 1e300
ex_rescaled = (ex * factor).astype(np.float64)
eigvals, eigvecs = np.linalg.eig(ex_rescaled)
eigvals = eigvals.astype(np.float128) / factor
# And to test...
check1 = ex.dot(eigvecs[:,0])
check2 = eigvals[0] * eigvecs[:,0]
print 'Checking accuracy..'
print check1, check2
print (check1 - check2).dot(check1 - check2), '<-- Should be zero'
最後に、2x2 または 3x3 のマトリックスのみを解く場合は、独自のソルバーを記述して、これらの形状のマトリックスの正確な値を返すことができます。
import numpy as np
def quadratic(a,b,c):
sqrt_part = np.lib.scimath.sqrt(b**2 - 4*a*c)
root1 = (-b + sqrt_part) / (2 * a)
root2 = (-b - sqrt_part) / (2 * a)
return root1, root2
def eigvals(matrix_2x2):
vals = np.zeros(2, dtype=matrix_2x2.dtype)
a,b,c,d = matrix_2x2.flatten()
vals[:] = quadratic(1.0, -(a+d), (a*d-b*c))
return vals
def eigvecs(matrix_2x2, vals):
a,b,c,d = matrix_2x2.flatten()
vecs = np.zeros_like(matrix_2x2)
if (b == 0.0) and (c == 0.0):
vecs[0,0], vecs[1,1] = 1.0, 1.0
elif c != 0.0:
vecs[0,:] = vals - d
vecs[1,:] = c
elif b != 0:
vecs[0,:] = b
vecs[1,:] = vals - a
return vecs
def eig_2x2(matrix_2x2):
vals = eigvals(matrix_2x2)
vecs = eigvecs(matrix_2x2, vals)
return vals, vecs
a = np.array([[-800.21,-600.00],[-600.00,-1000.48]], dtype=np.float128)
ex = np.exp(a)
eigvals, eigvecs = eig_2x2(ex)
# And to test...
check1 = ex.dot(eigvecs[:,0])
check2 = eigvals[0] * eigvecs[:,0]
print 'Checking accuracy..'
print check1, check2
print (check1 - check2).dot(check1 - check2), '<-- Should be zero'
これは真に正確な解を返しますが、2x2 行列に対してのみ機能します。ただし、これが実際に追加の精度の恩恵を受ける唯一のソリューションです。