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

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已经提供了所需功能的一部分。

最佳答案

介绍和定制功能
在浮点精度问题的一般情况下,建议使用公差值与可疑的零值进行比较,并且公差必须是非常小的值一个小的稳健方法将使用一个在其中使用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

08-24 15:48