MATLAB: I couldn’t understand why the code works with R=1.2 and d=3.6 values but doesn’t work with R=1.3 and d=3.9 values. Can you help me

conicalcylinderfloating pointfunctionMATLAB

function V=vol2(R,d)
if d<R
V=pi*d^3/3;
elseif d==R
V=pi*R^3/3;
elseif d>R && d<=(3*R)
V1=pi*R^3/3;
V2=pi*R^2*(d-R);
V=V1+V2;
elseif d>(3*R)
fprintf('Overtop!!')
end
end
Command
vol2(1.3,3.9)
ans=16.1049
vol(1.2,3.6)
Overtop!!

Best Answer

>> 1.2*3-3.6
ans =
-4.4409e-16
>> 1.3*3-3.9
ans =
4.4409e-16
>>
Neither are exact in the world of floating point and one case is rounding up while the other rounding down so the test is on either side by one significant bit.
Moral: don't do absolute comparisions on floating point values if rounding is important.
More background at ML FAQ Wiki: Why is 0.3-0.2-0.1 not zero?
ADDENDUM
Recast your function a little...
function V=vol2(R,d)
if d<R
V=pi*d^3/3;
elseif d==R
V=pi*R^3/3;
elseif d>R && (ismembertol(d,3*R) | d<=(3*R))
V1=pi*R^3/3;
V2=pi*R^2*(d-R);
V=V1+V2;
elseif d>(3*R)
fprintf('Overtop!!')
end
end
will handle the equal case within default epsilon for the input values and then the other NE cases are actually greater than that difference.
See the doc for ismembertol to set a specific magnitude of the tolerance factor it need to, the default is on the order of the precision of the inputs which is probably what you want here.
Illustration:
>> all(ismembertol(1.2*3,3.6),ismembertol(1.3*3,3.9))
ans =
logical
1
>>
Both of your trouble cases above are now actually in "equal" case.
One can write the above as
if abs(d,R)>eps
as well, of course, and was the solution before TMW introduced ismembertol instead of a fuzzy equals operator.