rounding errors in for loop

4 Ansichten (letzte 30 Tage)
Johannes
Johannes am 19 Apr. 2011
Hello, what is really happening under the hood?
How could one avoid rounding errors seen here?
>> test
input:0.3
comparison:0 <= 0.3 < 0.1
comparison:0.1 <= 0.3 < 0.2
comparison:0.2 <= 0.3 < 0.3
true
input:0.4
comparison:0 <= 0.4 < 0.1
comparison:0.1 <= 0.4 < 0.2
comparison:0.2 <= 0.4 < 0.3
comparison:0.3 <= 0.4 < 0.4
comparison:0.4 <= 0.4 < 0.5
true
input:0.5
comparison:0 <= 0.5 < 0.1
comparison:0.1 <= 0.5 < 0.2
comparison:0.2 <= 0.5 < 0.3
comparison:0.3 <= 0.5 < 0.4
comparison:0.4 <= 0.5 < 0.5
comparison:0.5 <= 0.5 < 0.6
true
input:0.7
comparison:0 <= 0.7 < 0.1
comparison:0.1 <= 0.7 < 0.2
comparison:0.2 <= 0.7 < 0.3
comparison:0.3 <= 0.7 < 0.4
comparison:0.4 <= 0.7 < 0.5
comparison:0.5 <= 0.7 < 0.6
comparison:0.6 <= 0.7 < 0.7
true
input:0.6
comparison:0 <= 0.6 < 0.1
comparison:0.1 <= 0.6 < 0.2
comparison:0.2 <= 0.6 < 0.3
comparison:0.3 <= 0.6 < 0.4
comparison:0.4 <= 0.6 < 0.5
comparison:0.5 <= 0.6 < 0.6
comparison:0.6 <= 0.6 < 0.7
comparison:0.7 <= 0.6 < 0.8
comparison:0.8 <= 0.6 < 0.9
comparison:0.9 <= 0.6 < 1
comparison failed
Error in ==> test>computeIndex at 10
disp(' ')
??? Output argument "ind" (and maybe others) not assigned
during call to ...
>> ver
-------------------------------------------------------------------------------------
MATLAB Version 7.10.0.499 (R2010a)
Operating System: Microsoft Windows XP Version 5.1 (Build 2600: Service Pack 3)
Java VM Version: Java 1.6.0_12-b04 with Sun Microsystems Inc. Java HotSpot(TM) Client VM mixed mode
function test
i3 = computeIndex(0.3);
i4 = computeIndex(0.4);
i5 = computeIndex(0.5);
i7 = computeIndex(0.7);
i6 = computeIndex(0.6);
end
function [ind] = computeIndex(meanValue)
disp(' ')
disp(['input:' num2str(meanValue)])
interval = 0.1; for i = 0:interval:0.9
uplimit = i + interval;
lowlimit = i;
disp([' comparison:' num2str(lowlimit) ' <= ' num2str(meanValue) ' < ' num2str(uplimit)])
if ( (meanValue >= lowlimit) && (meanValue < uplimit) )
ind = i;
disp('true')
return
end
end
disp('comparison failed')
end

Antworten (4)

Jan
Jan am 19 Apr. 2011

Oleg Komarov
Oleg Komarov am 19 Apr. 2011
I would use histc, it's more robust:
function ind = computeIndex(meanValue)
disp(' ')
disp(['input: ' num2str(meanValue)])
interval = 0.1;
ind = find(histc(meanValue,0:interval:1))-1;
if ind
lowB = 0:interval:interval*ind;
uppB = [lowB(2:end) lowB(end)+interval];
sprintf(' comparison: %2.1f <= %2.1f < %2.1f\n',...
[lowB; repmat(ind,1,ind+1); uppB])
else
disp('comparison failed')
end
end

Tim
Tim am 19 Apr. 2011
Hi, I won't put myself forward as the foremost expert here, but I can at least tell you where your problem is and how to avoid it. I apologise if it is only stuff you already know. Exactly what MATLABs mechanism is here is a little confusing to me.
The short answer on how to avoid it is to use integers. It's also not the answer anybody wants to hear, because it is annoying. Even double precision floating point numbers are not exact, because they are floating point. I guess you know this much already.
A slightly more helpful observation is that for your code to work here, you only have to avoid using floating point in ONE of these places; your FOR loop. The problem is NOT your input. You are already aware that floating point numbers are inexact, or you wouldn't have phrased your question as you did (I assume).
A third cure is below, but it is not, in my opinion, a great one. It ensures that you get a result by preserving the inaccuracy across tests.
function [ind] = computeIndex(meanValue)
disp(' ')
disp(['input:' num2str(meanValue)])
interval = 0.1;
lowlimit = 0; % <- Change here
uplimit = 0.1; % <- Change here
for i = 0:interval:0.9
%uplimit = i + interval;
%lowlimit = i;
disp([' comparison:' num2str(lowlimit) ' <= ' num2str(meanValue) ' < ' num2str(uplimit)])
if ( (meanValue >= lowlimit) && (meanValue < uplimit) )
ind = i;
disp('true')
return
end
lowlimit = uplimit; % <- Change here
uplimit = uplimit + 0.1; % <- Change here
end
disp('comparison failed')
%throw some error here
end
Here is where the problem is: lowlimit is NEVER == 0.6. It is slightly MORE.
Why? Well, it is likely that 0.1 is not exactly represented and therefore multiplying it by 6 gives a result more than 0.6. What is confusing is why THIS is the tipping point. Is there some error margin? 5 times 0.1 IS calculated as being equal to 0.5! Add another 0.1, and suddenly it isn't?! In short, I don't know why. My guess is a tolerance in the '>' operator, perhaps caused by changing precision before application or during application. This I would love to have answered too!
In simpler terms, explain these two MATLAB results, because I think THIS is the heart of the problem.
>> 5*0.1 + 0.1 == 0.6
ans =
1
>> 6*0.1 == 0.6
ans =
0

Robert Cumming
Robert Cumming am 19 Apr. 2011
I got around this type of problem by creating the following function which rounds numbers to user defined number of decimal places:
function output = dcp ( input, number )
output = round(input *10^number)/10^number;
end
i.e. when I repeat the simple example shown by Tim:
>> 5*0.1 + 0.1 == 0.6
ans =
1
>> 0.1 * 6 == 0.6
ans =
0
>> dcp(0.1 * 6,1) == 0.6
ans =
1

Kategorien

Mehr zu Get Started with Optimization Toolbox finden Sie in Help Center und File Exchange

Community Treasure Hunt

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

Start Hunting!

Translated by