second condition never gets executed - elseif (temp == 13.2) tried to run in 13b, 15b online edittors as well, any explanations or its a bug?

1 visualización (últimos 30 días)
for temp=0.0:0.01:20
if (temp == 13.19)
disp(temp);
elseif (temp == 13.2)
disp(temp);
elseif (temp == 13.21)
disp(temp);
end
end

Respuesta aceptada

Jan
Jan el 20 de Feb. de 2018
Editada: Jan el 20 de Feb. de 2018
This is not a bug, but the expected behavior of IEEE754 floating point values. See FAQ: Why is 0.3-0.2 not 0.1?
Matlab uses IEEE754 doubles, which are store in binary form internally. There is no exact conversion between binary and decimal numbers, if they are stores with a limited precision. One consequence is the rounding effect when numbers are added:
(0.1 + 0.1 + 0.1) - 0.3 % Not 0.0, but in the magnitude of eps
This has been asked hundred times already:
any((0.0:0.1:1.0) == 0.3) % FALSE
The solution is to use an interval, e.g.:
elseif abs(temp - 13.2) < 10 * eps(13.2)
disp(temp);
The limits of the interval depend on the specific problem.
Welcome to the world of numerics with limited precision.

Más respuestas (3)

Jos (10584)
Jos (10584) el 20 de Feb. de 2018
Welcome to the world of computers where it is tricky to compare floating point numbers. Take a look at the answer here: https://uk.mathworks.com/matlabcentral/answers/57444-faq-why-is-0-3-0-2-0-1-not-equal-to-zero
A better condition check is to use some tolerance
if abs(temp-13.21)<0.001

Steven Lord
Steven Lord el 20 de Feb. de 2018
This is NOT a bug. Read this Answer and especially the last section on this documentation page linked from that Answer.
Avoid using == to perform exact, down-to-the-last-bit comparisons between floating point numbers. Compare using a tolerance instead, or find a way to rewrite the comparison to avoid potential floating point issues.
for temp=0:2000 % Multiplied the temp variable by 100 so it takes on only integer values
if (temp == 1319)
disp(temp/100);
elseif (temp == 1320)
disp(temp/100);
elseif (temp == 1321)
disp(temp/100);
end
end
Or since you want to know if temp is one of a specific set of numbers, if you're using release R2015a or later you can use the ismembertol function:
for temp=0.0:0.01:20
if ismembertol(temp, [13.19 13.2 13.21], 1e-6)
disp(temp);
end
end

John BG
John BG el 24 de Feb. de 2018
Hi Rohit Kumar Gupta
As mentioned by the previous contributors, when using a float for this particular variable data range,
it's like using a CHEP pallet (1mx1.2m) in the warehouse
to send to store a couple of fish fingers boxes (very very small)
so it's not really efficient.
1.
One way around the 'universe' of float is to use a step:
clear all;clc;close all
temp_step=.01;
temp=[0.0:temp_step:20];
ntemp=[1:1:20/temp_step+1];
target1=13.91;
target2=13.20;
target3=13.21;
ntarget1=find(temp==target1);
ntarget2=find(temp==target2);
ntarget3=find(temp==target3);
for k=ntemp
if (k == ntarget1) disp(temp(k)); end;
if (k == ntarget2) disp(temp(k)); end;
if (k == ntarget3) disp(temp(k)); end;
end
13.199999999999999
13.210000000000001
13.910000000000000
MATLAB dully places the data you supply in the most significant digits of the float variables, but for the remaining digits that you have not defined?
MATLAB kind of very politely and implicitly says 'be my guest' and takes what from the machine point of view is a reasonable guess,
yet it may not be what you expect as answer.
2.
Types doubles and floats a great data formats, but for your question there's a better and obvious approach,
Use the right container:
Zero the resolution of the container used to the smallest tolerance required
this way, by including the tolerance in the step, we avoid the inherent problems that arise from using way too big containers for way to small data loads.
temp=uint32(temp/temp_step)
target1=13.91/temp_step;
target2=13.20/temp_step;
target3=13.21/temp_step;
ntarget1=find(temp==target1);
ntarget2=find(temp==target2);
ntarget3=find(temp==target3);
for k=ntemp
if (k == ntarget1) disp(double(temp(k))*temp_step); end;
if (k == ntarget2) disp(double(temp(k))*temp_step); end;
if (k == ntarget3) disp(double(temp(k))*temp_step); end;
end
13.200000000000001
13.210000000000001
13.910000000000000
3.
there's still a really tiny residue 1e-15.
If you want to really remove any trace below the 2nd decimal, we should use characters and present the results as
'13.20'
'13.21'
'13.91'
If you are interested to proceed this way please me know.
.
Rohit
if you find this answer useful would you please be so kind to consider marking my answer as Accepted Answer?
To any other reader, if you find this answer useful please consider clicking on the thumbs-up vote link
thanks in advance for time and attention
John BG

Categorías

Más información sobre Introduction to Installation and Licensing en Help Center y File Exchange.

Community Treasure Hunt

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

Start Hunting!

Translated by