Fun with Rounding

While you may remember the simple rounding rules you learning in school as a kid - there are in fact more complex rounding rules that are used in real life to overcome bias and errors in various scenarios.

Be Consistent

We want to use the same rounding function consistently so that we can avoid having conflicting values on account of rounding methods.

Method to Use: Math.Round(…)

Flow for Elector makes extensive use of the Math.Round() function when calculating the displayed values of various percentages (Vote %, Poll %, etc.).

We made changes in Flow build 15.5.2.3 to resolve inconsistencies in how we display rounded percent values.

// Sample results below: Math.Round(56.15, 1) = 56.2 Math.Round(56.25, 1) = 56.2 Math.Round(56.35, 1) = 56.4 Math.Round(56.45, 1) = 56.4 Math.Round(56.55, 1) = 56.6 Math.Round(56.65, 1) = 56.6

This is the default rounding mode used in IEEE 754 operations for results in binary floating-point formats.

Round to nearest, ties to even – rounds to the nearest value; if the number falls midway, it is rounded to the nearest value with an even least significant digit.

A tie-breaking rule without positive/negative bias and without bias toward/away from zero is round half to even. By this convention, if the fractional part of x is 0.5, then y is the even integer nearest to x. Thus, for example, +23.5 becomes +24, as does +24.5; however, −23.5 becomes −24, as does −24.5. This function minimizes the expected error when summing over rounded figures, even when the inputs are mostly positive or mostly negative, provided they are neither mostly even nor mostly odd.

This variant of the round-to-nearest method is also called convergent rounding, statistician's rounding, Dutch rounding, Gaussian rounding, odd–even rounding, or bankers' rounding.

(from Wikipedia)

Methods to Avoid

We want to avoid using the string formatting functions because they use a different rounding function.

The % placeholder

Don’t use the string format or string interpolation that relies on the % placeholder.

votePctString = votePct.ToString("#0.0%") // Sample results below: (0.5605).ToString("#0.0%") = "56.1%" (0.5615).ToString("#0.0%") = "56.2%" (0.5625).ToString("#0.0%") = "56.3%" (0.5635).ToString("#0.0%") = "56.4%" (0.5645).ToString("#0.0%") = "56.5%" (0.5655).ToString("#0.0%") = "56.6%"

The standard P format

If using the standard string format for percent indicated by P you can likewise trigger the rounding function that is different then Math.Round(…)

votePctString = string.Format("{0:P1}", votePct) The results are the same as the % placeholder above.