给定两个包含数值的向量,例如
a=1.:0.1:2.;
b=a+0.1;
我想只选择不同的值。为此,Matlab
提供了函数setdiff。在上面的示例中,很明显setdiff(a,b)
应该返回1.
而setdiff(b,a)
会返回2.1
。但是,由于计算精度(请参阅问题here或here),结果会有所不同。我得到了
>> setdiff(a,b)
ans =
1.0000 1.2000 1.4000 1.7000 1.9000
Matlab
提供了一个函数,它返回此精度错误eps的下限。这允许我们估算像tol = 100*eps;
我现在的问题是,是否有一种智能且有效的方法来仅选择那些差异低于tol
的值?或者换句话说:如何编写自己的setdiff
版本,返回值和索引,包括容差限制?
我不喜欢在question中回答它的方式,因为matlab已经提供了所需功能的一部分。
答案 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以包括其最接近的值。