Why 0.6 is not equal to 0.2*3 ??

Hello, I have question on a really simple code :
n=(0.2*3);
m=0.6;
a=m-n
if (m==n)
trial=1;
else
trial=0;
end
when i run this code, trial = 0 and a= -1.11*10^-16. I don' get why this erreur occures :
n=(0.2*3);
m=0.6;
a=m-n
if (m==n)
trial=1;
else
trial=0;
end
This code gives a=0 and trial=1 as expected. Have someone any idea of why this is happenning and how can i compare 0.6 to 0.2*3 to get an equality? Thank you !!

1 Comment

Stephen23
Stephen23 on 26 Jul 2017
Edited: Stephen23 on 26 Jul 2017
"Have someone any idea of why this is happenning"
The reason is basically because all numbers in your computer are stored as finite binary numbers, and they cannot represent exactly those decimal fractions (in just the same way that you cannot write 1/3 exactly using a finite decimal fraction).
Your code tests for equivalence of floating point values, which is a very buggy and unreliable way to write code. You need to change your algorithm to take into account floating point error:
etc, etc, etc

Sign in to comment.

Answers (1)

You need to learn more about floating point numbers:
In short, never use == to compare floating point numbers that come from different calculations. Always check their absolute difference against an arbitrarily small value:
if abs(m-n) <= 1e-15
AreEqual = true;
else
AreEequal = false;
end

7 Comments

Thank you Guillaume for your quick answer. Just to summurize, I am trying to manage a discretization using the find fonction in a loop which is used as incrementation.
for k=1:(a_max/pas)
a_reel=k*pas;
i=find(a_reel==alpha(:));
[...]
end
So i can't use this formalism. Do i have to create a vector which contains all my a_reel (exact values)? So how can i build it if i can't use calculation ? Thank you again !
@Magisstrane: as long as you keep thinking that you have "exact values" then you will have problems. Change your mindset and accept that binary encoded numbers are not the same as decimal fractions.
And Guillaume already told you how to handle this situation: compare the difference against some tolerance value. See Guillaume's answer and example code.
@Magistrane: Read the links provided by Stephen carefully. It is fundamental and essential for numerics to understand the nature of floatring point numbers stored with a limited precision.
You need:
dist = abs(a_reel - alpha(:));
i = find(dist < limit);
or
dist = abs(a_reel - alpha(:)) ./ max(abs(a_reel), abs(alpha(:)));
i = find(dist < limit);
for the absolute or relative distance. The limit and if relative or absolute distances are useful depends on your problem.
The numerical effects have an equivalent in the physical world also: You cannot determine the distance between New York City and Brisbane with a resolution of nanometers, because the location of a city is not defined with such a precision. Imagine a set of 100 marbels and you should find the subset, which has a certain distance from a specific point. Then how is "distance" defined "exactly"? Neither a point on the surface nor the center is defined with 100% accuracy and infinite precision. It is meaningless to solve such a problem with a resolution lower than the size of atoms.
It is worth reiterating what I and others have said: You cannot compare floating point numbers with ==
So yes, you will have to change your loop the way Jan has shown.
Or most likely, the loop is not even needed and you could use ismembertol either with the default tolerance, or one you specify to find all your values at once:
all_reels = pas:pas:a_max;
[found, where] = ismembertol(all_reels, alpha(:));
where will contain the first of your i for each of your a_reel values (so would be equivalent to i = find(x, 1, 'first') in your loop version). If you want a vector of indices for each a_reel as your code would have done if there were duplicate in alpha, you can add the 'OutputAllIndices', true option to ismembertol.
Thank you again for your anwer, At the end i used roundn() function which match with the utilisation in my algo. Until now, it works, should I expect other supprises with this? ^^" If you say yes, I surrend and will take hours to change my loop, other way, thank you again for the explanations it was really usefull! Have a good day!
@Magistrane: rounding introduces artificial artifacts into data because it groups data into powers of ten: this can force data values apart even though the data are much closer than the data tolerance. Compare:
>> V = [1.249,1.251];
>> diff(V)
ans = 0.002
>> roundn(V,1)
ans =
1.2 1.3
So even though the original data only differ by 0.002 (they can be arbitrarily close within floating point limits), they end up being rounded in totally different directions and have a final difference of 0.1 and would not be considered "identical" using your method. Lets say that the data/measurement tolerance is 0.05 which means that those rounded values are not matched by your method even though the original values differ by a value that is only 1/25 of the measurement tolerance! Comparing against the tolerance directly allows the values to be correctly matched:
>> abs(diff(V))<0.05
ans = 1
The converse also applies: data which are quite distinct relative to the measurement tolerance can get rounded together:
>> V = [1.151,1.249];
>> diff(V)
ans = 0.098000
>> roundn(V,1)
ans =
1.2000 1.2000
So your method groups data together that are separated by almost twice the measurement tolerance. Once again comparing against the tolerance yields a correct measure of how similar those values are:
>> abs(diff(V))<0.05
ans = 0
Summary: the best solution is to compare the difference against a tolerance.
If you're using release R2024b or later, you could use the isapprox function to determine if two numbers are approximately equal.

Sign in to comment.

Categories

Asked:

on 26 Jul 2017

Commented:

on 24 Jun 2025

Community Treasure Hunt

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

Start Hunting!