Strange behaviour of MATLAB find command

9 views (last 30 days)
Recently a lot of changes have happened on my computer and I have some issues with MATLAB. Now I use a local trial license and before I was on a local full license and before that was a floating license. I also have a new pc and lots of changes with the configuration etc. and because of this I am not able to track back to what the problem could be and ask for your help.
Some lines in old code have stopped working for reasons unknown.
I will give an example..
In the attached .mat file, there are 2 arrays, g and p. g is an array of 410 elements and p is a single element array = 2.6.
Two commands that should give the same result are
find(g==p); find(g==2.6);
but on my computer, they don’t. The second command returns 27, correctly and the first command returns an empty matrix.
I don’t know why, could it be the numeric settings on my laptop, like , and . for German and English.. Or if there is a difference between the way things are processed in the trial and full license.

Accepted Answer

Stephen23
Stephen23 on 24 Jan 2017
Edited: Stephen23 on 16 Feb 2022
This is not a strange behavior at all, it has nothing to do with find, and it has nothing to do with the changes on your computer. It occurs simply because two different values are not equal, that is all. This behavior is expected when comparing floating point values which are not the same. You might think that they are the same, but what you think is irrelevant to your computer. Lets have a look in detail:
>> find(g==p)
ans = []
Why does find not find any identical values? Because there are no identical values.
Lets have a look at the values that you think are the same but are not really:
>> fprintf('%.30f\n',p)
2.599999999999999644728632119950
>> fprintf('%.30f\n',g(27))
2.600000000000000088817841970013
Search this forum for "floating point equals", or start by reading these:
This is worth reading as well:
PS: the solution, as every of those links will tell you, is never compare for equality between floating point values, and always use a tolerance:
>> find(abs(g-p)<0.001)
ans = 27
  4 Comments
Stephen23
Stephen23 on 9 Apr 2017
Edited: Stephen23 on 10 Nov 2022
@avleed: do not use round. This is not a good solution because values which differ by only a very small amount can get rounded to two very different values, yet values which differ by large amount get rounded to the same value. Lets have a look at a simple example:
>> round([0.45,0.54,0.55],1)
ans =
0.5 0.5 0.6
The difference between the first two values is nine time larger than the difference between the second two values, yet round will force first two to be the same value (even though their difference is nearly a magnitude larger). This introduce artificial artifacts into your comparison, because the rounding direction depends on the absolute values, not on their difference relative to your data tolerances... and yet the relative comparison is what you are actually trying to achieve.
round is not a good solution because the comparison itself changes depending on the absolute values. In contrast when comparing against a tolerance this does not occur: values that differ by <=tolerance will be matched, thus the comparison itself not depend on how the absolute values of the inputs.
Stephen23
Stephen23 on 10 Nov 2022
Edited: Stephen23 on 10 Nov 2022
Here is a simple illustration of why ROUND is not a good approach. Consider these two simple vectors, whose corresponding elements differ by some small constant (less than our imaginary data precision of 2e-1):
A = 1.1:0.005:1.2
A = 1×21
1.1000 1.1050 1.1100 1.1150 1.1200 1.1250 1.1300 1.1350 1.1400 1.1450 1.1500 1.1550 1.1600 1.1650 1.1700 1.1750 1.1800 1.1850 1.1900 1.1950 1.2000
B = A + 0.01
B = 1×21
1.1100 1.1150 1.1200 1.1250 1.1300 1.1350 1.1400 1.1450 1.1500 1.1550 1.1600 1.1650 1.1700 1.1750 1.1800 1.1850 1.1900 1.1950 1.2000 1.2050 1.2100
Now lets use the numerically misleading but sadly ever-popular approach using ROUND:
X = round(A,1)==round(B,1)
X = 1×21 logical array
1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 1
Wait, why some or those comparisons returning FALSE? Even though the values of And B only differ by a value that is half of our accepted data precision, our comparison sometimes thinks that A and B do not match!
What happens if we try the recommended approach of comparing the absolute difference against a tolerance:
tol = 2e-1; % data precision
Y = abs(A-B)<tol
Y = 1×21 logical array
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
Ah, much better!
The cause is perhaps easier to see graphically, where we can see that sometimes ROUND rounds values towards each other (to the same value) and sometimes away from each other to different values:
M = [A(:),B(:)];
plot(M,'*-')
set(gca, 'NextPlot','add', 'ColorOrderIndex',1)
plot(round(M,1),'+-')

Sign in to comment.

More Answers (0)

Categories

Find more on Introduction to Installation and Licensing in Help Center and File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!