Why does == not work with decimal indexed for loop?

19 visualizzazioni (ultimi 30 giorni)
Hi everyone,
I am working with a simple data vector and I need to find the occurrences of certain values. Here is a simplified version of the code, which amounts to a for loop and an equality check:
data=[1.5 1.6 1.7 1.8 1.9 2 2.1 2.2];
%this does not work
for index=1.4:0.1:2.3
output=find(data==index)
end
%this works!
for index=1.5:0.1:2.2
output=find(data==index)
end
Running the code I see that in the first case, where only the first and last check should give an empty result, also other iterations give the "1×0 empty double row vector" output. For example, given that index=94.6 during debug, if I write the same line as "find(data==index)" it fails, if I write it with the corresponding index value it works (find(data==94.6) works). The positions where the check fails are always the same. The second for loop, with all the items matching, never fails.
Could it be a problem with the double format precision with logical operators? I have tried it in Matlab R2017a and R2013a, on different computers. I also tried to rewrite the same code without the find function, and the result is the same. If I change both data and index ranges, the behavior is the same but the check fails at different positions. All the numbers are in double format. If I multiply everything by 10, so that the numbers are integers, both loops work fine.
I would like to understand why, with decimal numbers, it doesn't work in just ONE case, the one where not all the numbers have a match.
  2 Commenti
Stephen23
Stephen23 il 7 Set 2017
giorgia calisti
giorgia calisti il 7 Set 2017
Thank you both José-Luis and Guillaume for your complete replies. I would accept both answers if I could, thanks again!

Accedi per commentare.

Risposta accettata

José-Luis
José-Luis il 7 Set 2017
Modificato: José-Luis il 7 Set 2017
From the documentation:
"x = j:i:k creates a regularly-spaced vector x using i as the increment between elements. The vector elements are roughly equal to [j,j+i,j+2*i,...,j+m*i] where m = fix((k-j)/i)."
Emphasis on the roughly equal : You are running into the joys of double precision arithmetic. You should avoid comparing double precision numbers directly and use a tolerance.
You could use eps() to determine an adequate order of magnitude for the tolerance.
  2 Commenti
Multiplexer
Multiplexer il 18 Nov 2024 alle 15:44
Hello,
How about situation like this? On my machine this code
%% Loop operation
for i=0:0.1:1
y = i-0.7
end
y = -0.7000
y = -0.6000
y = -0.5000
y = -0.4000
y = -0.3000
y = -0.2000
y = -0.1000
y = 1.1102e-16
y = 0.1000
y = 0.2000
y = 0.3000
expresses the floating-point numeircs problem at index i == 0.7, substraction is non-zero
But when I strip the code out of for loop
%% Vector operation
i =0:0.1:1;
y = i(8)-0.7
y = 0
it works "as expected" 0.7 - 0.7 = 0.
Why does the colon (range) operator used in for loop indexing leads to the eps problem but used outside of for loop does not?
Steven Lord
Steven Lord il 18 Nov 2024 alle 16:16
There is an optimization in the way for loops handle the loop expression where it doesn't have to create the vector explicitly. So you could have a loop that runs many more iterations than it's possible to store in a vector.
for k = 1:flintmax
% Technically this works, though it would take a LONG time
end
x = 1:flintmax; % This would error
I ran that for loop on my desktop and used Ctrl-C to break the loop after about 30 seconds. k was around 7e10 when I did, though flintmax is around 9e15. If I'd let it go for a while longer (roughly 35 days) it would have completed. That other command must create the vector explicitly, and that's not possible (and even if it was, your machine doesn't have the petabytes of memory required to store an array that size.)
>> x = 1:flintmax;
Requested array exceeds the maximum possible variable size.
There's a reason the Description section on the for documentation page lists "initVal:step:endVal" and "valArray" as separate syntaxes.
But the underlying message remains: you probably shouldn't use == for equality testing on floating point values or expect subtracting two numbers that appear to be the same to give exactly 0. If you're using release R2024b or later, use isapprox instead.

Accedi per commentare.

Più risposte (1)

Guillaume
Guillaume il 7 Set 2017
What you're seeing is expected and is inherent to the way numbers are stored on computers. You'll see the same behaviour with other programming languages.
This is actually a FAQ and is all down to the fact that numbers can't all be represented exactly (particularly 0.1).
The answer is then to never use == to compare floating point values (it's fine for integers) but always use a small tolerance appropriate for the magnitude of numbers you're using.
In your case:
tolerance = 1e-20; %much smaller than your numbers magnitude
for index = 1.4:0.1:2.3
output = find(abs(data - index) <= tolerance); %check that the difference between the numbers is smaller than the tolerance
end

Community Treasure Hunt

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

Start Hunting!

Translated by