- RT @mattyglesias: Look, just because Sessions hasn't actually been convicted of a crime is no reason we can't start seizing his property no… 8 hours ago
- Wow #DUNKIRK was pretty amazing. Go see it. 12 hours ago
- RT @FullFrontalSamB: “Sean Spicer crawled to freedom through five hundred yards of shit smelling foulness I can’t even imagine…” https://t.… 1 day ago
- RT @dotnetkicks: Creating a GitHub Issues Autoresponder using Webask.io by @NotMyself dotnetkicks.com/r/253540?url=h… #dotnet via @DotNetKicks 1 day ago
- RT @databozo: Doing a thing for school. If you have a kid and use(d) formula, mind taking a survey? surveymonkey.com/r/XHKFN6S 2 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.