在 64 位系统上,有一个numpy.float128
dtype。float96
(我相信32 位系统上也有dtype)虽然numpy.linalg.eig
不支持 128 位浮点数,但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,一种解决方法是在求幂之后但在求解特征值之前重新缩放事物,将它们转换为“正常”浮点数,求解特征值,然后将事物重新转换为 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 矩阵。然而,这是唯一真正受益于额外精度的解决方案!