MATLAB: Does the while loop not work for this specific data-set

analysisdatafunctionloopwhile loop

I have written the following function, that effectively adjusts rounding errors. The code appears to get stuck in a while loop despite the condition of sum(roundedAssetAllocation) == 1. Could someone help to explain why?
function [a, n] = fixRounding(x, s)
u = 10.^-s;
n = length(x);
assetAllocation = x/sum(x);
roundedAssetAllocation = round(assetAllocation, s);
while sum(roundedAssetAllocation) ~= 1
diffFromUnrounded = assetAllocation - roundedAssetAllocation;
if sum(roundedAssetAllocation) < 1
[~, index] = max(diffFromUnrounded);
roundedAssetAllocation(index) = roundedAssetAllocation(index) + u;
elseif sum(roundedAssetAllocation) > 1
[~, index] = min(diffFromUnrounded);
roundedAssetAllocation(index) = roundedAssetAllocation(index) - u;
end
a = roundedAssetAllocation;
end
end
The following call should return: [.3485, .1198, .1356, .1761, .2200], but it instead gets stuck in a loop.
fixRounding([0.837746777686794, 0.287856637640281, 0.325810457772455, 0.423276428672838, 0.528787529659317], 4)

Best Answer

First, note that there is a bug in your code. If the while loop never get entered (if the sum is already exactly 1), then a never gets created.
The problem is a basic one of floating point operations. It is extremely difficult to equate the sum of numbers to a given number due to the precision of floating point numbers.
Had you stepped through your code you would have seen that on the 2nd iteration of the loop, the sum differs from 1 by only 2.2204e-16. No matter how much 0.0001 you add or subtract you're never going to get to one.
The solution would be to round the sum before comparing to one. Since the smallest value you add or subtract is 1e-s. round the sum to s decimals:
while round(sum(roundedAssetAllocation), s) ~= 1
And never use == or ~= to compare unrounded floating point numbers. round the numbers or use a small tolerance:
while abs(sum(roundedAssetAllocation) - 1) <= u