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 (최근 30일)
이전 댓글 표시
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
댓글 수: 1
Stephen23
2018년 2월 20일
"its a bug?"
No bug.
Small differences in the floating-point values mean that those values are actually different. Floating-point numbers have been explained a thousand times on this forum:
etc, etc, etc
Always use a tolerance when comparing floating point values.
채택된 답변
Jan
2018년 2월 20일
편집: Jan
2018년 2월 20일
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.
댓글 수: 0
추가 답변 (3개)
Jos (10584)
2018년 2월 20일
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
댓글 수: 0
Steven Lord
2018년 2월 20일
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
댓글 수: 0
John BG
2018년 2월 24일
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
댓글 수: 0
참고 항목
카테고리
Help Center 및 File Exchange에서 Logical에 대해 자세히 알아보기
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!