- 25 hours to Bariloche, but the views are worth it. https://t.co/7W7cN2t1sm 23 hours ago
- RT @SaintGimp: GWB: "No democracy pretends to be a tyranny. Most tyrannies pretend to be democracies. Democracy remains definition of polit… 2 days ago
- Seattle, WA ✈️ Atlanta, GA ✈️ Buenos Aires, Argentina ✈️ San Carlos de Baroloche, Argentina #AdventureTime @nodeconfar we are on our way! 2 days ago
- RT @aaronpk: Super happy to announce that my book "OAuth 2.0 Simplified" is now available! oauth2simplified.com 3 days ago
- RT @GraceStarling4: For those carrying their #MeToo with them silently, you are loved, cherished, and believed. You do not owe your story t… 4 days ago

# I Am Not Myself

Bills.Pay(Developer.Skills).ShouldBeTrue()

## In This Post We Remember You Can Do Math With Computers

June 3, 2011

Posted by on I recently ran into an interesting problem. I’ll try to describe the problem with out going into specific details of the domain the problem lives in. Let’s say I have a list of elements and each element have a property called weight that contains a decimal that represents that elements percentage in the entire list. If you sum the weights it should add up to 1M or 100%. This list of elements was loaded up from a text file and the text file weight had a precision of nine meaning that the number was represented with nine numbers after the decimal, 0.000000000. With this list I need to modify the precision to six and still have the sum of the weights add up to 100% exactly.

Here is what I came up with.

public class WeightRounder { private const int SIGNIFIGANT_DIGITS = 6; public IList<element> RoundOff(IList<element> elements) { if (elements.Count > 0) { MakeRoundedElements(elements); RedistributeWeightError(elements, GetTotalWeightError(elements)); } return model; } private static void MakeRoundedModel(IEnumerable<element> elements) { model.Each(x => x.UpstreamWeight = Math.Round(x.Weight, SIGNIFIGANT_DIGITS)); } private void RedistributeWeightError(IEnumerable<element> elements, decimal totalWeightError) { int errorSign = Math.Sign(totalWeightError); decimal step = (decimal) Math.Pow(10, -SIGNIFIGANT_DIGITS)*errorSign; elements.OrderByDescending(x => x.UpstreamWeight) .TakeWhile(x => Math.Abs(totalWeightError) > decimal.Zero) .Each(x => { x.UpstreamWeight += step; totalWeightError -= step; }); //indicates the elements were nowhere near 100% to begin with. if (totalWeightError != 0) throw new ApplicationException("Rounding failed. Total weight error {0} was to large to handle.".FormatWith(totalWeightError)); } private decimal GetTotalWeightError(IEnumerable<element> elements) { var totalWeightError = decimal.One; elements.Each(x => totalWeightError -= x.UpstreamWeight); return totalWeightError; } }

Thoughts, comments or rants on my general approach and math skills appreciated.

Boy does that look scary familiar. One thing I’ve found kind of interesting is that if you ask enough people about how to round something, eventually you’ll find the guy that actually knows math and can explain the pros and cons of different methods for redistributing error. In the above case, I think the idea is to overweight the larger weights, where the additional weight is not as significant. Not that it really matters, but a more robust, better way to do this might be to try to even out the statistical significance of each “error point”. I.e., if you had .9997 and .0001 as weights, adding one point to .9997 and then one point to .0001 results in the second weight being 50% larger when it would have been better to give the extra weight to the first weight where it hardly matters.

Woh…I think I need a drink now.

it should look familiar, i pretty much ripped it right out of fusion. After staring at it for a while to understand it.