简体   繁体   English

numpy矩阵求逆四舍五入错误

[英]numpy matrix inversion rounding errors

I am getting a very strange value for my (1,1) entry for my BinvA matrix 我的BinvA矩阵的(1,1)条目获得非常奇怪的值
I am just trying to invert B matrix and do a (B^-1)A multiplication. 我只是想将B矩阵求逆,并进行(B ^ -1)A乘法。

I understand that when I do the calculation by hand my (1,1) is supposed to be 0 but instead I get 1.11022302e-16. 我知道,当我手动进行计算时,我的(1,1)应该为0,但我得到1.11022302e-16。 How can I fix it? 我该如何解决? I know floating point numbers can't be represented to full accuracy but why is this giving me such an inaccurate response and not rounding to 0 is there any way I can make it more accurate? 我知道浮点数不能完全准确地表示出来,但是为什么这会给我这样一个不准确的响应,而不能四舍五入到0,有什么办法可以使我更准确呢?

Her is my code: 她是我的代码:

import numpy as np

A = np.array([[2,2],[4,-1]],np.int)
A = A.transpose()


B = np.array([[1,3],[-1,-1]],np.int)
B = B.transpose()

Binv = np.linalg.inv(B) #calculate the inverse

BinvA = np.dot(Binv,A) 
print(BinvA)

My print statement: 我的印刷声明:

[[  1.11022302e-16  -2.50000000e+00]
 [ -2.00000000e+00  -6.50000000e+00]]

When you compute the inverse your arrays are converted in float64 , whose machine epsilon is 1e-15. 计算逆时,数组将在float64中转换,其机器epsilon为1e-15。 The epsilon is the relative quantization step of a floating-point number. ε是浮点数的相对量化步骤

When in doubt we can ask numpy information about a floating-point data type using the finfo function. 如有疑问,我们可以使用finfo函数询问有关浮点数据类型的numpy信息。 In this case 在这种情况下

np.finfo('float64')
finfo(resolution=1e-15, 
      min=-1.7976931348623157e+308, max=1.7976931348623157e+308, 
      dtype=float64)

So, technically, your value being smaller than eps is a very accurate representation of 0 for a float64 type. 因此,从技术上讲,对于float64类型,您的值小于eps可以非常精确地表示为0。

If it is only the representation that bothers you, you can tell numpy to don't print small floating point numbers (1 eps or less from 0) with: 如果仅是表示困扰您,您可以告诉numpy不要打印小的浮点数(0到1 eps或更小):

np.set_printoptions(suppress=True)

After that your print statement returns: 之后,您的打印语句返回:

[[ 0.  -2.5]
 [-2.  -6.5]]

Note that this is a general numerical problem common to all the floating-point implementations. 请注意,这是所有浮点实现共有的通用数值问题。 You can find more info about floating-point rounding errors on SO: 您可以找到有关SO上浮点舍入错误的更多信息:

or on the net: 或在网上:

This isn't a complete answer, but it may point you in the right direction. 这不是一个完整的答案,但可能会为您指明正确的方向。 What you really want are numpy arrays that use Decimals for math. 您真正想要的是使用Decimals进行数学运算的numpy数组。 You might reasonably think to try: 您可能会合理地考虑尝试:

import numpy as np
from decimal import Decimal
A = np.array([[2,2],[4,-1]],np.int)
for i, a in np.ndenumerate(A):
    A[i] = Decimal(a)
    print type(A[i])

But alas, Decimals are not among the datatypes supported out of the box in numpy, so each time you try to jam a Decimal into the array, it re-casts it as a float. 但是,可惜的是,十进制不在 numpy 的现成支持数据类型之列 ,因此,每次尝试将十进制卡入数组时,它都会将其重新转换为浮点数。

One possibility would be to set the datatype, thus: 一种可能性是设置数据类型,因此:

def decimal_array(arr):
    X = np.array(arr, dtype = Decimal)
    for i, x in np.ndenumerate(X): X[i] = Decimal(x)
    return X

A = decimal_array([[2,2],[4,-1]])
B = decimal_array([[1,3],[-1,-1]])

A = A.transpose()
B = B.transpose()
Binv = np.linalg.inv(B) #calculate the inverse

But now, if you 但是现在,如果你

print Binv.dtype

you'll see that the inversion has recast it back to float. 您会看到反转已将其重铸为浮动状态。 The reason is that linalg.inv (like many other functions) looks for B's "common_type," which is the scalar to which it believe it can force your array elements. 原因是linalg.inv(与许多其他函数一样)寻找B的“ common_type”,它是B认为可以强制执行数组元素的标量。

It may not be hopeless, though. 不过,这可能并非没有希望。 I looked to see if you could solve this by creating a custom dtype, but it turns out that scalars (ints, floats, etc) are not dtypes at all. 我看了看是否可以通过创建自定义dtype来解决此问题,但事实证明,标量(int,float等)根本不是dtype。 Instead, what you probably want to do is register a new scalar--that's the Decimal--as it says in the article on scalars . 相反,您可能想做的就是注册一个新的标量,即Decimal,如有关标量文章中所述。 You'll see a link out to the Numpy C-API (don't be afraid). 您会看到一个指向Numpy C-API的链接(不用担心)。 Search the page for "register" and "scalar" to get started. 在页面上搜索“注册”和“标量”以开始使用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM