Python与MATLAB - 处理接近机器精度的数字

时间:2016-12-06 19:22:23

标签: matlab python-3.x precision

我知道有一些帖子有类似的主题。但是,我还没有找到任何不是特定问题和更一般的问题。

请,我不是在找一个解决方法 - 即"如果"声明如果足够接近,则强制值为零。

在我的问题中,我正在研究将矩阵转换为Hessenberg形式的结果(即应用变换将零引入矩阵 - 这里的数学细节不是问题)。我最初在MATLAB中为一个类编写了代码,现在也希望在Python中使用代码(所有使用基本操作 - 没有"黑盒"这里的操作)。我已经成功地完成了这项任务,但是对于应该为零的条目,我得到的答案却略有不同。

例如:

一些应为零的条目报告为1.77635684e-15和4.44089210e-16 - 它们都接近机器精度2.2204460E-16。

这有什么根本原因吗?

修改

稍微改善一下我的问题......

我最终得到的是减去几乎相等的数字 - 我知道一般来说这是一个坏主意 - 对于那些值应该为零的条目。因为它们几乎相等且非常小,所以存在精度损失的形式。

这让我觉得MATLAB和python如何处理这样的评估可能会有所不同......

编辑编辑

这是困扰我的输出(" py" = Python输出," mat" = MATLAB输出)。我可以忍受差异达到〜第15位 - 这是机器精度。困扰我的是第四栏。这里是几乎相等数量的减法发挥作用的地方,我们真正看到了差异(第2-4行是相互负面的!)

Python vs MATLAB output comparison

供参考,这是我的python代码:

A = [[1.,2.,3.,4.],[5.,6.,7.,8.],[9.,10.,11.,12.],[13.,14.,15.,16.]]
test = fctns.hess(A)
print(test)

def hess(A):
# This function reduces any mxm matrix to Hessenberg form
# through orthogonality similarity transforms. For symmetric A, the
# Hessenberg form will be tridiagonal.

dumA = np.array(A)
n = np.shape(dumA)[1] # obtains n in (m,n) matrix
v = []

for k in np.arange(0,n-2):
    x = np.zeros((n-(k+1),1))
    for idx in np.arange(0,len(x)):
        x[idx]=dumA[k+1+idx,k]
    tmp = np.shape(x)[0]
    if np.sign(x[0][0]) == 0:
        tmpsign = 1;
    else:
        tmpsign = np.sign(x[0][0]);
    dum = tmpsign*norm(x,tmp)*np.eye(tmp,1) + x;
    v.append(dum/norm(dum,tmp));
    dumA[k+1:,k:] = dumA[k+1:,k:] - 2*np.dot(v[k],np.dot(np.transpose(v[k]),dumA[k+1:,k:]));
    dumA[:,k+1:] = dumA[:,k+1:] - 2*np.dot(np.dot(dumA[:,k+1:],v[k]),np.transpose(v[k]));

return(dumA)

这是我的MATLAB代码:

function [ dumA ] = tridiag( A0 )
% This function reduces any mxm matrix to tridiagonal form
% through orthogonality similarity transforms. For symmetric cases, the
% Hessenberg form will be tridiagonal.

dumA = A0;
tmp = size(dumA);
m = tmp(1);
v = cell(1,length(1:m-2));

for k = 1:m-2
  x = dumA(k+1:m,k);
  tmp = size(x);
  if sign(x(1)) == 0
    tmpsign = 1;
  else
    tmpsign = sign(x(1));
  end
  dum = tmpsign*norm(x,2)*eye(tmp(1),1) + x;
  if sum(x) == 0
    v{k} = dum;
    continue
  end
  v{k} = dum/norm(dum,2);
  dumA(k+1:m,k:m) = dumA(k+1:m,k:m) - 2*v{k}*(v{k}'*dumA(k+1:m,k:m));
  dumA(1:m,k+1:m) = dumA(1:m,k+1:m) - 2*(dumA(1:m,k+1:m)*v{k})*v{k}';
end
end

1 个答案:

答案 0 :(得分:0)

您的python代码无法按原样运行,并且与MATLAB代码不同。我修好了:

dumA = np.array(A)
n = np.shape(dumA)[1] # obtains n in (m,n) matrix
v = []
for k in np.arange(n-2):
    x = dumA[k+1:,k:k+1]
    tmp = np.shape(x)[0]
    tmpsign = np.sign(x[0]);
    if not tmpsign:
        tmpsign = 1.
    dum = tmpsign*norm(x,2)*np.eye(tmp,1) + x;
    if not x.sum():
        v.append(dum)
        continue
    v.append(dum/norm(dum,2));
    dumA[k+1:,k:] -= 2.*(v[k] @ (v[k].T @ dumA[k+1:,k:]));
    dumA[:,k+1:] -= 2.*((dumA[:,k+1:] @ v[k]) @ v[k].T);
print(dumA)

我做了一些测试,对于第一次迭代,一切都是相同的,直到循环的倒数第二行(从dumA到倒数第二次)。此代码出现此问题:dumA[:,k+1:] @ v[k]dumA(1:m,k+1:m)*v{k}。矩阵乘积的最后一个元素有一个非常小的数值差异,约为2e-16。这可能归结为略有不同的实现。

MATLAB和numpy似乎都在使用相同版本的MKL进行计算,但由于无法看到MATLAB源代码,因此无法准确说出其差异所在。