Why does == not work with decimal indexed for loop?
19 visualizzazioni (ultimi 30 giorni)
Mostra commenti meno recenti
giorgia calisti
il 7 Set 2017
Commentato: Steven Lord
il 18 Nov 2024 alle 16:16
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
il 7 Set 2017
Never use == to test for equivalence of decimal values. Always compare the difference against a tolerance:
abs(A-B)<tol
And some external links on this topic:
Risposta accettata
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
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
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
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
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.
Più risposte (1)
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
0 Commenti
Vedere anche
Categorie
Scopri di più su Distributed Arrays in Help Center e File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!