Matlab - 将矢量与setdiff进行比较,同时忽略eps下的精度

时间:2014-07-31 13:27:06

标签: matlab matrix floating-point comparison precision

给定两个包含数值的向量,例如

a=1.:0.1:2.;
b=a+0.1;

我想只选择不同的值。为此,Matlab提供了函数setdiff。在上面的示例中,很明显setdiff(a,b)应该返回1.setdiff(b,a)会返回2.1。但是,由于计算精度(请参阅问题herehere),结果会有所不同。我得到了

>> setdiff(a,b)
   ans = 
      1.0000 1.2000 1.4000 1.7000 1.9000

Matlab提供了一个函数,它返回此精度错误eps的下限。这允许我们估算像tol = 100*eps;

这样的容差

我现在的问题是,是否有一种智能且有效的方法来仅选择那些差异低于tol的值?或者换句话说:如何编写自己的setdiff版本,返回值和索引,包括容差限制?

我不喜欢在question中回答它的方式,因为matlab已经提供了所需功能的一部分。

2 个答案:

答案 0 :(得分:2)

简介和自定义功能

在浮点精度问题的一般情况下,建议使用容差值来比较可疑的零值,并且容差必须是非常小的值。一个有点强大的方法将使用在其中使用eps的容差。现在,由于MATLAB基本上使用setdiff执行减法,因此您可以通过比较小于或等于它来直接使用eps来查找zeros

这构成了此处显示的修改后的setdiff for floating point numbers的基础 -

function [C,IA] = setdiff_fp(A,B)
%//SETDIFF_FP Set difference for floating point numbers.
%//   C = SETDIFF_FP(A,B) for vectors A and B, returns the values in A that 
%//   are not in B with no repetitions. C will be sorted.
%//
%//   [C,IA] = SETDIFF_FP(A,B) also returns an index vector IA such that
%//   C = A(IA). If there are repeated values in A that are not in B, then
%//   the index of the first occurrence of each repeated value is returned.

%// Get 2D matrix of absolute difference between each element of A against 
%// each element of B
abs_diff_mat = abs(bsxfun(@minus,A,B.')); %//'

%// Compare each element against eps to "negate" the floating point
%// precision issues. Thus, we have a binary array of true comparisons.
abs_diff_mat_epscmp = abs_diff_mat<=eps;

%// Find indices of A that are exclusive to it
A_ind = ~any(abs_diff_mat_epscmp,1);

%// Get unique(to account for no repetitions and being sorted) exclusive 
%// A elements for the final output alongwith the indices
[C,IA] = intersect(A,unique(A(A_ind)));

return;

示例运行

案例1(有整数)

这将验证setdiff_fp是否与setdiff的方式一起使用整数数组。

A = [2 5];
B = [9 8 8 1 2 1 1 5];
[C_setdiff,IA_setdiff] = setdiff(B,A)
[C_setdiff_fp,IA_setdiff_fp] = setdiff_fp(B,A)

<强>输出

A =
     2     5
B =
     9     8     8     1     2     1     1     5
C_setdiff =
     1     8     9
IA_setdiff =
     4
     2
     1
C_setdiff_fp =
     1     8     9
IA_setdiff_fp =
     4
     2
     1

案例2(带浮点数)

这表明setdiff_fp会产生正确的结果,而setdiff则不会。此外,这还将测试输出指数。

A=1.:0.1:1.5
B=[A+0.1 5.5 5.5 2.6]
[C_setdiff,IA_setdiff] = setdiff(B,A)
[C_setdiff_fp,IA_setdiff_fp] = setdiff_fp(B,A)

<强>输出

A =
    1.0000    1.1000    1.2000    1.3000    1.4000    1.5000
B =
    1.1000    1.2000    1.3000    1.4000    1.5000    1.6000    5.5000    5.5000    2.6000
C_setdiff =
    1.2000    1.4000    1.6000    2.6000    5.5000
IA_setdiff =
     2
     4
     6
     9
     7
C_setdiff_fp =
    1.6000    2.6000    5.5000
IA_setdiff_fp =
     6
     9
     7

答案 1 :(得分:0)

容忍1 epsilon这应该有效:

a=1.0:0.1:2.0;
b=a+0.1;
b=[b b-eps b+eps];
c=setdiff(a,b)

我们的想法是扩展b以包括其最接近的值。