Thread Subject: ismember - getting wrong result

Subject: ismember - getting wrong result

From: Ashwini Deshpande

Date: 12 Mar, 2009 13:04:01

Message: 1 of 22

Hi,

I have a matrix as follows,

a = 0:0.1:1;

when i tried to find whether 0.300 is present in the matrix 'a', using following procedure,
>> [tf, loc]=ismember(0.3,a)

i got the following result:
tf =
     0
loc =
     0
But it suppose to give me, tf = 1 and loc =4.

Can anyone tell me, what is the problem and how to overcome it..
Thanks !
Ashwini
 

Subject: ismember - getting wrong result

From: us

Date: 12 Mar, 2009 13:12:02

Message: 2 of 22

"Ashwini Deshpande"
> I have a matrix as follows,
> a = 0:0.1:1;
> when i tried to find whether 0.300 is present in the matrix 'a', using following procedure,
> >> [tf, loc]=ismember(0.3,a)
> i got the following result...

you get the CORRECT result, of course...

% look what happens
     v=0:.1:1;
     n=0.3;
     sprintf('%30.20f\n',v(4),n)
%{
     0.30000000000000004000 % <- result from vec
     0.29999999999999999000 % <- result from handwritten number
%}
     format hex;
     [v(4),n,v(4)-n].'
%{
     3fd3333333333334 % <- vec
     3fd3333333333333 % <- num
     3c90000000000000 % <- diff
%}
     format;

% also, peruse

http://matlabwiki.mathworks.com/MATLAB_FAQ#Why_is_0.3-0.2-0.1_not_equal_to_zero_.28or_similar.29.3F

us

Subject: ismember - getting wrong result

From: Pj

Date: 12 Mar, 2009 13:15:09

Message: 3 of 22

"Ashwini Deshpande" <vd.ashwini@mathworks.com> wrote in message <gpb180$5uv$1@fred.mathworks.com>...
> Hi,
>
> I have a matrix as follows,
>
> a = 0:0.1:1;
>
> when i tried to find whether 0.300 is present in the matrix 'a', using following procedure,
> >> [tf, loc]=ismember(0.3,a)
>
> i got the following result:
> tf =
> 0
> loc =
> 0
> But it suppose to give me, tf = 1 and loc =4.
>
> Can anyone tell me, what is the problem and how to overcome it..
> Thanks !
> Ashwini
>

a(4)-0.3

ans =

    5.551115123125783e-017

A precision problem.

Subject: ismember - getting wrong result

From: Pj

Date: 12 Mar, 2009 13:25:06

Message: 4 of 22

"Ashwini Deshpande" <vd.ashwini@mathworks.com> wrote in message <gpb180$5uv$1@fred.mathworks.com>...
> Hi,
>
> I have a matrix as follows,
>
> a = 0:0.1:1;
>
> when i tried to find whether 0.300 is present in the matrix 'a', using following procedure,
> >> [tf, loc]=ismember(0.3,a)
>
> i got the following result:
> tf =
> 0
> loc =
> 0
> But it suppose to give me, tf = 1 and loc =4.
>
> Can anyone tell me, what is the problem and how to overcome it..
> Thanks !
> Ashwini
>

Try:
>> a=0:10;
>> a=a/10;
>> ismember(a, 0.3)

ans =

     0 0 0 1 0 0 0 0 0 0 0

Subject: ismember - getting wrong result

From: Jos

Date: 12 Mar, 2009 13:52:02

Message: 5 of 22

"Pj " <northern69@yahoo.com> wrote in message <gpb2fi$t9e$1@fred.mathworks.com>...
> "Ashwini Deshpande" <vd.ashwini@mathworks.com> wrote in message <gpb180$5uv$1@fred.mathworks.com>...
<SNIP ... FP problem with ismember

> Try:
> >> a=0:10;
> >> a=a/10;
> >> ismember(a, 0.3)
>
> ans =
>
> 0 0 0 1 0 0 0 0 0 0 0

Poor advise! Do not rely on this. It may work here, but fails elsewhere.

a = 1:10 ; a = a/10 ;
ismember(a, 0.3)
ismember(a-0.1, 0.2)

One is better off understanding the limitations of computer systems in representing numbers.

Jos

Subject: ismember - getting wrong result

From: Ashwini Deshpande

Date: 13 Mar, 2009 04:27:01

Message: 6 of 22

"Ashwini Deshpande" <vd.ashwini@mathworks.com> wrote in message <gpb180$5uv$1@fred.mathworks.com>...
> Hi,
>
> I have a matrix as follows,
>
> a = 0:0.1:1;
>
> when i tried to find whether 0.300 is present in the matrix 'a', using following procedure,
> >> [tf, loc]=ismember(0.3,a)
>
> i got the following result:
> tf =
> 0
> loc =
> 0
> But it suppose to give me, tf = 1 and loc =4.
>
> Can anyone tell me, what is the problem and how to overcome it..
> Thanks !
> Ashwini
>

Thanks for all replies ..

I tried another method of rounding off the values for example,

a=0.1:0.1:1;
a1 = round(a*10)/10;

[tf, loc] = ismember((round(0.3*10)/10), a1);

and it also works well ...

Thanks again

Ashwini

Subject: ismember - getting wrong result

From: Walter Roberson

Date: 14 Mar, 2009 07:33:06

Message: 7 of 22

Ashwini Deshpande wrote:
 
> I tried another method of rounding off the values for example,
>
> a=0.1:0.1:1;
> a1 = round(a*10)/10;
>
> [tf, loc] = ismember((round(0.3*10)/10), a1);
>
> and it also works well ...


No, that's broken too -- it just hasn't bit you yet.

Unless you are a floating point guru, never compare floating point
numbers for exact equality (which ismember does implicitly): instead,
compare with a tolerance. Even when your code appears to calculate two
floating point number by using the same expression, Matlab is permitted
to rewrite the expressions for that -it- thinks is optimal -- or you
could hit a problem such as "register spill". (If you don't know what
"register spill" is and why it is a problem, you don't know enough
about floating point to know when to break the rules.)

Subject: ismember - getting wrong result

From: Bruno Luong

Date: 14 Mar, 2009 15:44:01

Message: 8 of 22

I would like to offer a code called ismemberf, similar to ismember but with tolerance.
It is a little slow for 'row' option. Not sure how to accelerate it.

This could endup in FEX one day.

function varargout = ismemberf(A, S, varargin)
% function tf = ismemberf(A, S)
% [tf loc ] = ismemberf(A, S)
%
% Purpose: Floating point ISMEMBER (i.e., with round-off tolerance)
%
% ismemberf(A, S, 'row') operate on row
% ismemberf(..., 'tol', tol) fix the tolerance
% tol can be scalar or vector (using with 'row')
%
% If not provided, tol is 1e-10 relative to variations of S values
%
% Example:
% [X Y]=meshgrid(0:0.1:10,0:0.1:10);
% S=[3 1;
% 3 3;
% 5 6;
% 5.2 5.5;
% 3 3];
% A = [X(:) Y(:)];
% [tf loc]=ismemberf(A, S, 'row', 'tol', 0.5);
% imagesc(reshape(loc,size(X)));


% Call native ismember for strings
if ~isnumeric(A) || ~isnumeric(S)
    out = cell(1,max(nargout,1));
    [out{:}] = ismember(A, S, varargin{:});
    varargout = out;
    return
end

% Preprocess the optional inputs (for parsing later on)
vin = varargin;
for k=1:length(vin)
    if ischar(vin{k})
        vin{k} = strtrim(lower(vin{k}));
    else
        vin{k}='';
    end
end

% parsing the varargin to set tol
tol = [];
tolloc = strmatch('tol', vin);
if ~isempty(tolloc)
    tolloc = tolloc(end);
    if length(vin)>=tolloc+1
        tol = varargin{tolloc+1};
    end
end

% one dimensional ismember
if isempty(strmatch('row', vin))
    [tf loc] = ismember1(A, S, tol);
    
else % row option
    % Check fo compatible dimension
    if size(A,2) ~= size(S,2)
        error('A and S must have the same number of columns');
    end
    
    % duplicate tol
    if isempty(tol)
        tol(1:size(A,2)) = {};
    elseif isscalar(tol)
        tol(1:size(A,2)) = tol;
    end

    % Loop over column
    B = true;
    for j=1:size(A,2)
        % Get the binary matrix
        [tfj locj Bj] = ismember1(A(:,j), S(:,j), tol(j));
        B = B & Bj;
    end
    [iA iS] = find(B);
    tf = false(size(A,1),1);
    tf(iA) = true;
    loc = accumarray(iA,iS,size(tf),@(i) max(i));
end

% Process output
[out{1:2}] = deal(tf, loc);
nout = min(max(nargout,1), length(out));
varargout(1:nout) = out(1:nout);

end

function [tf loc B] = ismember1(A, S, tol)

    [Su I J] = unique(S(:),'last');
    
    % Set the tolerance
    if isempty(tol)
        maxS = max(Su);
        minS = min(Su);
        if maxS == minS
            tol = 1e-10;
        else
            tol = (maxS - minS)*1e-10;
        end
    else
        tol=tol(1);
    end
    xlo = Su - tol;
    xhi = Su + tol;
    [dummy ilo] = histc(A, [xlo; Inf]);
    [dummy ihi] = histc(A, [-Inf; xhi]);
    tf = ilo & ihi & (ilo >= ihi);
    loc = zeros(size(tf));
    loc(tf) = I(ilo(tf));
    %
    % Building a logical matrix of boolean B of size (m x n)
    % where m = numel(A), n = numel(S)
    % B(m,n) is true if two elements in A(m) and S(n) is "identical"
    %
    if nargout>=3
        left = ihi(tf);
        right = ilo(tf);
        % index in S
        % Group all the index of S when they map to the same Su
        II = accumarray(J(:), (1:numel(S)).', [length(Su) 1], @(x) {x});
        iS = arrayfun(@(l,r) cat(1,II{l:r}).', left, right, ...
                      'UniformOutput', false);
        nele = cellfun(@length, iS);
        iS = [iS{:}]; % concatenate
        % index in A
        iA = cumsum(accumarray(cumsum([1; nele]),1));
        iA(end)=[];
        inonly = find(tf);
        iA = inonly(iA);
        B = sparse(iA,iS,true,numel(A),numel(S));
    end
end

Subject: ismember - getting wrong result

From: Bruno Luong

Date: 15 Mar, 2009 12:25:03

Message: 9 of 22

I have optimize the code (mostly for speed). Before I submit to FEX, I would like to get your feedback.

Just save the bellow to a single mfile ismemberf.m and try it.

Thanks,

Bruno
 
function varargout = ismemberf(A, S, varargin)
% function tf = ismemberf(A, S)
% [tf loc] = ismemberf(A, S)
%
% Purpose: Floating-point ISMEMBER (i.e., with round-off tolerance)
% See help ISMEMBER (Matlab buit-in function) for more detail about calling
% Note that Matlab ISMEMBER uses strict exact comparison between floats.
%
% ismemberf(A, S, 'row') operates on rows of A and S (2D arrays)
% and returns true (1) if they match, false (0) otherwise.
% ismemberf(..., 'tol', tol) select a suitable the tolerance
% - tol can be scalar or vector (using with 'row')
% - When tol is vector, each element is applied to a specific
% column of A and S
% - If not provided, or NaN, tol is 1e-10 relative to variations
% of S values (separation for each column of S)
% - When tol is provided as zero, ISMEMBERF calls Matlab ISMEMBER
%
% Examples:
%
% [tf, loc]=ismemberf(0.3, 0:0.1:1) % <- This return 0 by ISMEMBER
%
% [X Y]=meshgrid(0:0.1:10,0:0.1:10);
% S=[3 1;
% 3 3;
% 5 6;
% 5.2 5.5;
% 3 3];
% A = [X(:) Y(:)];
% [tf loc]=ismemberf(A, S, 'row', 'tol', 0.5);
% imagesc(reshape(loc,size(X)));
%
% Author: Bruno Luong <brunoluong@yahoo.com>
% Original: 15/March/2009


% Call the native Matlab ismember for strings
if ~isnumeric(A) || ~isnumeric(S)
    out = cell(1,max(nargout,1));
    [out{:}] = ismember(A, S, varargin{:});
    varargout = out;
    return
end

% Preprocess the optional inputs (for parsing later on)
vin = varargin;
for k=1:length(vin)
    if ischar(vin{k})
        vin{k} = strtrim(lower(vin{k}));
    else
        vin{k}='';
    end
end

% parsing the varargin to set tol
tol = NaN; % <- automatic tolerancce, see ismember1 bellow
tolloc = strmatch('tol', vin);
if ~isempty(tolloc)
    tolloc = tolloc(end);
    if length(vin)>=tolloc+1
        tol = varargin{tolloc+1};
        if ~isnumeric(tol)
            error('tolerance must be a number');
        end
    else
        error('tolerance value is not provided');
    end
end

% No tolerance, call Matlab ismember for array
if all(tol==0)
    out = cell(1,max(nargout,1));
    % Remove tolerance parameters, not supported by Matlab
    v=varargin;
    v(tolloc:tolloc+1)=[];
    [out{:}] = ismember(A, S, v{:});
    varargout = out;
    return
end

% one dimensional ismember
if isempty(strmatch('row', vin))
    [tf loc] = ismember1(A, S, tol);
    
else % row option
    % Check fo compatible dimension
    if ndims(A) ~= 2 || ndims(A) ~= 2
        error('A and S must be 2-dimensional arrays');
    end
    if size(A,2) ~= size(S,2)
        error('A and S must have the same number of columns');
    end
    if isempty(S) % Few exception cases
        tf = false(size(A,1),1);
        loc = zeros(size(tf));
        if size(S,2)==0 % Hah, compare a 0-dimensional set is always true
            tf(:) = true;
            loc(:) = 1;
        end
    else % S must not be empty
        % duplicate tol if necessary
        if isempty(tol)
            tol = nan(size(A,2),1);
        elseif isscalar(tol)
            tol(1:size(A,2)) = tol;
        end
        
        % Loop over column (dimension)
        B = true;
        for j=1:size(A,2)
            % Get the binary matrix
            [tfj locj Bj] = ismember1(A(:,j), S(:,j), tol(j));
            B = B & Bj;
        end
        [iA iS] = find(B);
        tf = false(size(A,1),1);
        tf(iA) = true;
        if isempty(iS)
            loc = zeros(size(tf));
        else
            % This seems to be faster than max inside accumarray
            B = accumarray([iA(:),iS(:)], iS(:), size(B));
            loc = max(B,[],2);
            %loc = accumarray(iA(:),iS(:),size(tf),@(j) max(j));
        end
    end % if empty(S)
end % row option

% Process output
[out{1:2}] = deal(tf, loc);
nout = min(max(nargout,1), length(out));
varargout(1:nout) = out(1:nout);

end % ismemberf


% Nested function, working linearly
function [tf loc B] = ismember1(A, S, tol)

    % Work only on subset of S, Su is sorted
    [Su I J] = unique(S(:),'last');
    
    % Set the tolerance automatically
    if isempty(tol) || isnan(tol)
        maxS = max(Su);
        minS = min(Su);
        if maxS == minS
            tol = 1e-10;
        else
            tol = (maxS - minS)*1e-10;
        end
    else
        tol=tol(1);
    end
    
    % Take a braket [-tol,tol] round each element
    xlo = Su - tol;
    xhi = Su + tol;
    % Look where points in A are located
    [dummy ilo] = histc(A, [xlo; Inf]);
    [dummy ihi] = histc(A, [-Inf; xhi]);
    % Test if they belong to the bracket
    tf = ilo & ihi & (ilo >= ihi);
    
    % ilo is the last indice
    loc = zeros(size(tf));
    loc(tf) = I(ilo(tf));
    %
    % Building a logical matrix of boolean B of size (m x n)
    % where m = numel(A), n = numel(S)
    % B(m,n) is true if two elements in A(m) and S(n) is "identical"
    %
    if nargout>=3
        % index in S
        % Group all the index of S when they map to the same Su
        left = ihi(tf);
        right = ilo(tf);

        % Find the index in S, duplicated by number of elements in A
        % belong to it
        [iS nele] = getiS(left(:), right(:), J);
    
        % index in A
        % This is a trick to generate the same vector long as iS
        % with a ids (1, 2, 3...) repeated for each cell elements (of
        % length nele)
        iA = cumsum(accumarray(cumsum([1; nele]),1));
        
        inonly = find(tf);
        iA = inonly(iA(1:end-1));
        
        % Logical matrix, in sparse
        B = sparse(iA(:),iS(:),true,numel(A),numel(S));
    end % if nargout>=3
    
end % ismember1

function [Icat lengthII] = Jsubset(J)
% J is an array from the third argument of UNIQUE (mapping index)
% Group the mapping J by subset (in Icat), each subset has the length
% stored in lengthII. The subset are sorted.
% In other word, perform equivalent to the following:
% (but optimized for speed)
% II = accumarray(J(:), (1:numel(J)).', [max(J) 1], @(x) {x});
% Icat = cat(1,II{:});
% lengthII = cellfun(@length, II)

[Js Icat]=sort(J(:));
n=Js(end);
m=length(J);

jump=diff([0; Js(:)])>0;
last=zeros(n,1);
last(Js(jump)) = diff([find(jump); m+1]);
lengthII=diff([0; cumsum(last)]);

end % Jsubset

function [v csl] = catbraket(l, r)
% Concatenate I1:=(l(1):r(1))', I2=(l(2):r(2)', etc ...
% in v = [I1; I2; ... ]
% Note: at the entrance r(i) must be l(i)-1 for empty braket

    if isempty(l)
        v = [];
        csl = 1;
        return
    end
    l=l(:);
    r=r(:);
    csl=cumsum([0; r-l]+1);

    v = accumarray(csl(1:end-1), (l-[0; r(1:end-1)]-1));
    % Adjust the size of v
    sv = csl(end)-1; % wanted length
    if size(v,1)>sv
        v(sv+1:end)=[];
    elseif size(v,1)<sv % pad zero
        v(sv)=0;
    end
    v = cumsum(v+1);
    %[l r v]
end % catbraket

function [iS nele] = getiS(left, right, J)
% Do this (but avoid cell to improve speed)
% iS = arrayfun(@(l,r) cat(1,II{l:r}).', left, right, ...
% 'UniformOutput', false);
% nele = cellfun(@length, iS);
% iS = [iS{:}]; % concatenate in a long row vector
% This is awfully hard to read, because of the optimization
    
    [Icat lengthII] = Jsubset(J);
    % Do the following
    % is1 = arrayfun(@(l,r) (l:r).', left, right, ...
    % 'UniformOutput', false);
    % is1 = cat(1,is1{:});
    [is1 csl] = catbraket(left, right);
    
    % Compute the length of each subset in iS
    % nele(k) will be length of cat(1,II{left(k):right(k)})
    csIIis = cumsum([0; lengthII(is1)]);
    nele = csIIis(csl(2:end))-csIIis(csl(1:end-1));
    
    % Build the left/right brakets when II cells will be expanded
    ss=cumsum([0; lengthII])+1;
    l=ss(is1);
    r=ss(is1+1)-1;
    
    % Last step, concatenate II and retrieve data in the braket
    %
    iS = Icat(catbraket(l, r));

end % getiS

Subject: ismember - getting wrong result

From: Jan Simon

Date: 15 Mar, 2009 22:28:00

Message: 10 of 22

Dear Bruno Luong!

> I have optimize the code (mostly for speed). Before I submit to FEX, I would like to get your feedback.

Your approach does match the needs. In my eyes, the short question should by answered by a short algorith. What do you think of this version:

------------------------------------- 8<---------------------------
function [AEx, BI] = ismemberf(A, B, Tol)
% Jan Simon, 15-Mar-2009
AEx = false(size(A));
nA = numel(A);
nB = numel(B);
if nA
   if nargout == 1 % Create BI on demand only
      if nA <= nB
         B = B(:);
         for iA = 1:nA
            AEx(iA) = any(abs(B - A(iA)) <= Tol);
         end
      else % Faster for: nB < nA
         A = A(:);
         on = true; % Slightly faster to call the function TRUE once only
         for iB = 1:nB
            AEx(abs(B(iB) - A) <= Tol) = on;
         end
      end
      
   else % Create BI in addition:
      on = true;
      BI = zeros(size(A));
      B = B(:);
      for iA = 1:nA
         match = (abs(B - A(iA)) <= Tol);
         if any(match)
            AEx(iA) = on;
            matchInd = find(match);
            BI(iA) = matchInd(length(matchInd));
         end
      end
   end
end

return;
---------------------------------------------------->8--------------------

The different branches for increasing the speed let this grow a little bit. It should be easy to change the check from absolute to relative tolerance, e.g.:
  (abs(B - A(iA)) / A(iA) <= Tol)

Thanks to Matlab's JIT this piece of code might be fast enough for the demands.
I'd hesitate to copy this to the FEX, because it is not smart at all. But it works and its simplicity might be helpful for beginners.

Questions: Is this still true in R2009a:
  matchInd(length(matchInd)) is faster than
  matchInd(end) is faster than
  find(match, 1, 'last') ?

Kind regards, Jan

Subject: ismember - getting wrong result

From: Niklas

Date: 15 Mar, 2009 23:58:01

Message: 11 of 22

try linspace. it works for me:

a=linspace(0,1,11)
[b,c]=ismember(0.3,a)


Answer:
b =
     1
c =
     4

Subject: ismember - getting wrong result

From: Bruno Luong

Date: 16 Mar, 2009 07:42:09

Message: 12 of 22

"Niklas " <nn@hotmail.com> wrote in message <gpk4m9$7mg$1@fred.mathworks.com>...
> try linspace. it works for me:
>
> a=linspace(0,1,11)
> [b,c]=ismember(0.3,a)
>
>
> Answer:
> b =
> 1
> c =
> 4

You are simply lucky that day.

>> a=linspace(0.1,1,10);
>> [b,c]=ismember(0.7,a)
b =
     0
c =
     0
>> [b,c]=ismemberf(0.7,a)
b =
     1
c =
     7

% Bruno

Subject: ismember - getting wrong result

From: Bruno Luong

Date: 16 Mar, 2009 08:51:08

Message: 13 of 22

"Jan Simon" <matlab.THIS_YEAR@nMINUSsimon.de> wrote in message <gpjvdg$p4b$1@fred.mathworks.com>...

>
> Thanks to Matlab's JIT this piece of code might be fast enough for the demands.
> I'd hesitate to copy this to the FEX, because it is not smart at all. But it works and its simplicity might be helpful for beginners.

Hi Jan,

Yes. I get your point. Your code is simple enough to be understood by beginners, that's a big plus.

Thanks,

Bruno

Subject: ismember - getting wrong result

From: Pete

Date: 16 Mar, 2009 12:06:15

Message: 14 of 22

"us " <us@neurol.unizh.ch> wrote in message <gpb1n2$851$1@fred.mathworks.com>...
.....
> % also, peruse
>
> http://matlabwiki.mathworks.com/MATLAB_FAQ#Why_is_0.3-0.2-0.1_not_equal_to_zero_.28or_similar.29.3F
>
> us

I found that link interesting. I guess the colon operator is more complicated than I had realised. Despite being aware of floating point considerations, I had found the behaviour of ismember (at least in 2008a) a bit odd at times, e.g.

ismember(0:.1:.5, 0:.1:.5)
ans =
     1 1 1 1 1 1
>> ismember(0:.1:.5, 0:.1:.6)
ans =
     1 1 1 1 0 1
>> ismember(0:.1:.5, 0:.1:.7)
ans =
     1 1 1 0 0 0

Subject: ismember - getting wrong result

From: Jos

Date: 16 Mar, 2009 12:41:13

Message: 15 of 22

"Pete " <pete.dot.bankhead@btinternet.dot.com> wrote in message <gplfbn$3sp$1@fred.mathworks.com>...
> "us " <us@neurol.unizh.ch> wrote in message <gpb1n2$851$1@fred.mathworks.com>...
> .....
> > % also, peruse
> >
> > http://matlabwiki.mathworks.com/MATLAB_FAQ#Why_is_0.3-0.2-0.1_not_equal_to_zero_.28or_similar.29.3F
> >
> > us
>
> I found that link interesting. I guess the colon operator is more complicated than I had realised. Despite being aware of floating point considerations, I had found the behaviour of ismember (at least in 2008a) a bit odd at times, e.g.
>
> ismember(0:.1:.5, 0:.1:.5)
> ans =
> 1 1 1 1 1 1
> >> ismember(0:.1:.5, 0:.1:.6)
> ans =
> 1 1 1 1 0 1
> >> ismember(0:.1:.5, 0:.1:.7)
> ans =
> 1 1 1 0 0 0

(again) it is not ismember, it is the colon operator behaving not as you (sic!) expect

a = [0:.1:.5]
b = [0:.1:.6]
[a .6] == b

Jos

Subject: ismember - getting wrong result

From: Pete

Date: 16 Mar, 2009 12:41:14

Message: 16 of 22

For a concise, stripped-down alternative to ismember with a tolerance, you could use

function tf = ismem_tol(A, S, tol)
d = bsxfun(@minus, A(:), S(:)');
tf = any(abs(d) <= tol, 2);
tf = reshape(tf, size(A));


There's no 'rows' option or second output (which would be the index of the last nonzero column in each row of abs(d) <= tol), and I suppose it's not very memory efficient for large inputs, but it's short and simple.

Subject: ismember - getting wrong result

From: Bruno Luong

Date: 16 Mar, 2009 12:59:16

Message: 17 of 22

"Jos " <#10584@fileexchange.com> wrote in message <gplhd9$fkq$1@fred.mathworks.com>...

>
> (again) it is not ismember, it is the colon operator behaving not as you (sic!) expect
>

How column works? I can't see it.

a = [0:.1:.5]
b = [0:.1:.6]

diff(a)==0.1
 % ans = 1 1 0 0 0

diff(b)==0.1
% ans = 1 1 0 0 0 0

d1=mean(diff(a))
d2=mean(diff(b(1:5)))
d3=mean(diff(b(1:6)))
d4=mean(diff(b(1:7)))

[d1 d2 d3 d4] == 0.1
% ans = 1 0 1 0

[d1 d2 d3 d4]==d2
% ans = 0 1 0 1

Bruno

Subject: ismember - getting wrong result

From: Pete

Date: 16 Mar, 2009 13:48:17

Message: 18 of 22

"Jos " <#10584@fileexchange.com> wrote in message <gplhd9$fkq$1@fred.mathworks.com>...
> "Pete " <pete.dot.bankhead@btinternet.dot.com> wrote in message <gplfbn$3sp$1@fred.mathworks.com>...
> > "us " <us@neurol.unizh.ch> wrote in message <gpb1n2$851$1@fred.mathworks.com>...
> > .....
> > > % also, peruse
> > >
> > > http://matlabwiki.mathworks.com/MATLAB_FAQ#Why_is_0.3-0.2-0.1_not_equal_to_zero_.28or_similar.29.3F
> > >
> > > us
> >
> > I found that link interesting. I guess the colon operator is more complicated than I had realised. Despite being aware of floating point considerations, I had found the behaviour of ismember (at least in 2008a) a bit odd at times, e.g.
> >
> > ismember(0:.1:.5, 0:.1:.5)
> > ans =
> > 1 1 1 1 1 1
> > >> ismember(0:.1:.5, 0:.1:.6)
> > ans =
> > 1 1 1 1 0 1
> > >> ismember(0:.1:.5, 0:.1:.7)
> > ans =
> > 1 1 1 0 0 0
>
> (again) it is not ismember, it is the colon operator behaving not as you (sic!) expect
>
> a = [0:.1:.5]
> b = [0:.1:.6]
> [a .6] == b
>
> Jos


I realise that. That's why I wrote 'I guess the colon operator is more complicated than I had realised', although I first noticed the issue when using ismember. Even taking floating point issues into account, I would have (wrongly) expected the colon operator to use the same approximation for the corresponding numbers in each vector in the examples I gave (differing only in their end values). I suppose there is some sense to why this does not happen, but it would not have occurred to me beforehand to consider it, and the changing location of the differences seemed strange. I see the explanation is given in
http://www.mathworks.com/support/solutions/data/1-4FLI96.html?solution=1-4FLI96

(sic!)?

Subject: ismember - getting wrong result

From: Jos

Date: 16 Mar, 2009 14:56:15

Message: 19 of 22

"Pete " <pete.dot.bankhead@btinternet.dot.com> wrote in message <gpllb1$328$1@fred.mathworks.com>...
> "Jos " <#10584@fileexchange.com> wrote in message

> > (again) it is not ismember, it is the colon operator behaving not as you (sic!) expect

> (sic!)?

Hi Peter,

It's latin, meaning to emphasize that is literally you (as a user) who is confused by the result. The colon operator is behaving as expected, or rather, it is has been programmed.

Good reference, by the way!

Best,
Jos

Subject: ismember - getting wrong result

From: Peter Boettcher

Date: 16 Mar, 2009 15:17:43

Message: 20 of 22

"Jos " <#10584@fileexchange.com> writes:

> "Pete " <pete.dot.bankhead@btinternet.dot.com> wrote in message <gpllb1$328$1@fred.mathworks.com>...
>> "Jos " <#10584@fileexchange.com> wrote in message
>
>> > (again) it is not ismember, it is the colon operator behaving not as you (sic!) expect
>
>> (sic!)?

> It's latin, meaning to emphasize that is literally you (as a user) who
> is confused by the result. The colon operator is behaving as expected,
> or rather, it is has been programmed.

I'm not sure that's a correct usage of sic!

http://en.wikipedia.org/wiki/Sic


-Peter

Subject: ismember - getting wrong result

From: Jos

Date: 16 Mar, 2009 21:33:01

Message: 21 of 22

Peter Boettcher <boettcher@ll.mit.edu> wrote in message <muyskldijjc.fsf@G99-Boettcher.llan.ll.mit.edu>...
> "Jos " <#10584@fileexchange.com> writes:
>
> > "Pete " <pete.dot.bankhead@btinternet.dot.com> wrote in message <gpllb1$328$1@fred.mathworks.com>...
> >> "Jos " <#10584@fileexchange.com> wrote in message
> >
> >> > (again) it is not ismember, it is the colon operator behaving not as you (sic!) expect
> >
> >> (sic!)?
>
> > It's latin, meaning to emphasize that is literally you (as a user) who
> > is confused by the result. The colon operator is behaving as expected,
> > or rather, it is has been programmed.
>
> I'm not sure that's a correct usage of sic!
>
> http://en.wikipedia.org/wiki/Sic
>
>
> -Peter

Peter,

You're right. I think that usage of "sic!" differs a little bit in dutch and english; in dutch sentences, one can use "(sic!)" to emphasize something (besides being ironic or literally quoting) and it serves the same purpose as "(!)". I meant it to be interpreted in that way only. (for a bonus point: guess what I speak at home ...)

Jos

Subject: ismember - getting wrong result

From: Pete

Date: 16 Mar, 2009 22:21:01

Message: 22 of 22

Thanks Jos and Peter! I feel I've been enlightened by this thread in more ways than I could have predicted when I opened it this morning.
Goede nacht,
Pete

Tags for this Thread

Everyone's Tags:

Add a New Tag:

Separated by commas
Ex.: root locus, bode

What are tags?

A tag is like a keyword or category label associated with each thread. Tags make it easier for you to find threads of interest.

Anyone can tag a thread. Tags are public and visible to everyone.

Tag Activity for This Thread
Tag Applied By Date/Time
precision Phil 12 Mar, 2009 09:20:05
code us 12 Mar, 2009 09:15:06
reference us 12 Mar, 2009 09:15:06
fp us 12 Mar, 2009 09:15:06
floating point us 12 Mar, 2009 09:15:06
evergreen us 12 Mar, 2009 09:15:06
ismember Ashwini Deshpande 12 Mar, 2009 09:04:06
rssFeed for this Thread
 

MATLAB Central Terms of Use

NOTICE: Any content you submit to MATLAB Central, including personal information, is not subject to the protections which may be afforded information collected under other sections of The MathWorks, Inc. Web site. You are entirely responsible for all content that you upload, post, e-mail, transmit or otherwise make available via MATLAB Central. The MathWorks does not control the content posted by visitors to MATLAB Central and, does not guarantee the accuracy, integrity, or quality of such content. Under no circumstances will The MathWorks be liable in any way for any content not authored by The MathWorks, or any loss or damage of any kind incurred as a result of the use of any content posted, e-mailed, transmitted or otherwise made available via MATLAB Central. Read the complete Terms prior to use.

Contact us at files@mathworks.com