Velocity Reviews > Rounding a number to nearest even

# Rounding a number to nearest even

Mark Dickinson
Guest
Posts: n/a

 04-11-2008
On Apr 11, 10:29 am, hdante <(E-Mail Removed)> wrote:
> Strangely, a "faster" version is:
>
> def fast_round(x):
> if x % 1 != 0.5: return round(x)
> return 2.0*round(x/2.0)

You should be a little bit careful with the test
x%1 == 0.5 if x might be negative:

>>> x = -0.5 + 2**-54
>>> x # not an exact half...

-0.49999999999999994
>>> x % 1 # ... and yet x%1 == 0.5

0.5

But for x positive, it should be safe. And for this
particular application, it turns out that it doesn't
matter: it gives the right result for this input anyway.

Mark

Lie
Guest
Posts: n/a

 04-11-2008
On Apr 11, 10:19 pm, Mikael Olofsson <(E-Mail Removed)> wrote:
> (E-Mail Removed) commented about rounding towards even numbers
> from mid-way between integers as opposed to for instance always rounding
> up in those cases:
>
> > Strange request though, why do you need it that way, because 2.5 is
> > CLOSER to 3 than to 2...

>
> That's exactly how I was taught to do rounding in what-ever low-level
> class it was. The idea is to avoid a bias, which assumes that the
> original values are already quantized. Assume that we have values
> quantized to one decimal only, and assume that all values of this
> decimal are equally likely. Also assume that the integer part of our
> numbers are equally likely to be even or odd. Then the average rounding
> error when rounding to integers will be 0.05 if you always round up when
> the decimal is 5. If you round towards an even number instead when the
> decimal is 5, then you will round up half of those times, and round down
> the other half, and the average rounding error will be 0. That's the
> idea. Of course you could argue that it would be even more fair to make
> the choice based on the tossing of a fair coin.

That old-school rounding method you're taught is based on a wrong
assumption of the nature of number. In the past, rounding algorithm is
based on this:

Original => (RoundUp(u|d|n), RoundNearestEven(u|d|n)
....
1.0 => 1(n), 1(n)
1.1 => 1(d), 1(d)
1.2 => 1(d), 1(d)
1.3 => 1(d), 1(d)
1.4 => 1(d), 1(d)
1.5 => 2(u), 2(u)
1.6 => 2(u), 2(u)
1.7 => 2(u), 2(u)
1.8 => 2(u), 2(u)
1.9 => 2(u), 2(u)
2.0 => 2(n), 2(n)
2.1 => 2(d), 2(d)
2.2 => 2(d), 2(d)
2.3 => 2(d), 2(d)
2.4 => 2(d), 2(d)
2.5 => 3(u), 2(d)
2.6 => 3(u), 3(u)
2.7 => 3(u), 3(u)
2.8 => 3(u), 3(u)
2.9 => 3(u), 3(u)
....

In this used-to-be-thought-correct table, Round Ups algorithm have 2
Unrounded, 8 Round Down, and 10 Round Ups which seems incorrect while
Round Even have 2 Unrounded, 9 Round Down, and 9 Round Up which seems
correct. The misunderstanding comes from a view that thinks that there
is such thing as Not Rounded while in fact the only number that is Not
Rounded is 1 and 2 while 1.0 and 2.0 must still be rounded, in
practice we can just say that all number must be rounded somewhere.

Original => (RoundUp(u|d), RoundNearestEven(u|d)
....
1.0 => 1(d), 1(d)
1.1 => 1(d), 1(d)
1.2 => 1(d), 1(d)
1.3 => 1(d), 1(d)
1.4 => 1(d), 1(d)
1.5 => 2(u), 2(u)
1.6 => 2(u), 2(u)
1.7 => 2(u), 2(u)
1.8 => 2(u), 2(u)
1.9 => 2(u), 2(u)
2.0 => 2(d), 2(d)
2.1 => 2(d), 2(d)
2.2 => 2(d), 2(d)
2.3 => 2(d), 2(d)
2.4 => 2(d), 2(d)
2.5 => 3(u), 2(d)
2.6 => 3(u), 3(u)
2.7 => 3(u), 3(u)
2.8 => 3(u), 3(u)
2.9 => 3(u), 3(u)
....

In this table, we consider that a number is rounded down when the
number is equal to truncated value (the number without fractional
part), while round up is equal to truncated value + 1 or truncated
value -1 if value is negative (Actually this is not round-half-up
algorithm, it's a round-half-away-from-zero algorithm, but lets just
consider that to be the same for now). In this revised table, you get
10 round ups and 10 round down (i.e. Average Rounding Error == 0),
while by rounding to nearest even you get 9 round up and 11 round down
(i.e. Average Rounding Error != 0).

> Note that if you do not have quantized values and assuming that the
> fraction part is evenly distributed between 0 and 1, than this whole
> argument is moot. The probability of getting exactly 0.5 is zero in that
> case, just as the probability of getting any other specified number is zero.

Another mistake, in an unquantized value the probability of getting
exactly 0.5 (or any other number specified) is not 0 but an
infinitesimal (i.e. lim(x) where x -> 0 (BUT NOT ZERO))

> That said, measurements are in practice always quantized, and rounding
> towards an even number when mid-way between avoids an average error of
> half the original precision.

> As a side-note: The the smallest coin in Swedish currency SEK is 0.50,
> but prices in stores are given with two decimals, i.e. with precision
> 0.01. But what if your goods add up to 12.34? The standard in Swedish
> stores, after adding the prices of your goods, is to round the number to
> the nearest whole or half SEK, which means that decimals 25 and 75 are
> mid-way between. In those cases the rounding is usually done to the
> nearest whole SEK, which is based on precicely the above reasoning. If
> they did not do that, I could argue that they are stealing on average
> 0.005 SEK from me every time I go to the store. Well... I could live
> with that, since 0.005 SEK is a ridiculously small amount, and even if I
> make thousands of such transactions per year, it still sums up to a
> neglectable amount.

No the reason is not that, it's because 1) it is much easier to input
integral numbers to computer (calculator or cashier machine), to
input .5 to computer you have to press two more buttons or at least
one shortcut button and 2) if you have two lists, one with a bunch of .
5's and the other just a few of them you would know that it's easier
to sum the latter list with or without calculator.

> Another side-note: My 12-year old son is now being taught to always
> round up from mid-way between. Yet another example of the degradation of
> maths in schools.

A false assertion from a false understanding. The use of Round Up
algorithm is a refinement of the false understanding we used to
practice in the past.

Mark Dickinson
Guest
Posts: n/a

 04-11-2008
On Apr 11, 2:33*pm, Lie <(E-Mail Removed)> wrote:
> In this table, we consider that a number is rounded down when the
> number is equal to truncated value (the number without fractional
> part), while round up is equal to truncated value + 1 or truncated
> value -1 if value is negative (Actually this is not round-half-up
> algorithm, it's a round-half-away-from-zero algorithm, but lets just
> consider that to be the same for now). In this revised table, you get
> 10 round ups and 10 round down (i.e. Average Rounding Error == 0),
> while by rounding to nearest even you get 9 round up and 11 round down
> (i.e. Average Rounding Error != 0).

No: if you interpret average to mean 'mean' (add up the (signed)
rounding errors from the 20 cases you list and divide by 20) you'll
find that the average rounding error is indeed 0 for round-half-to-
even,
and 0.05 for round-half-away-from-0, just as Mikael said.

> Another mistake, in an unquantized value the probability of getting
> exactly 0.5 (or any other number specified) is not 0 but an
> infinitesimal (i.e. lim(x) where x -> 0 (BUT NOT ZERO))

I'm not sure you'll get many takers for this point of view. If X is
a random variable uniformly distributed on the interval [0, 1) then
the probability that X == 0.5 is indeed exactly 0, using conventional
definitions. (And if you're not using conventional definitions, you
should say so....)

Mark

Gabriel Genellina
Guest
Posts: n/a

 04-11-2008
On 11 abr, 15:33, Lie <(E-Mail Removed)> wrote:
> On Apr 11, 10:19 pm, Mikael Olofsson <(E-Mail Removed)> wrote:

> > That's exactly how I was taught to do rounding in what-ever low-level
> > class it was. The idea is to avoid a bias, which assumes that the
> > original values are already quantized. Assume that we have values
> > quantized to one decimal only, and assume that all values of this
> > decimal are equally likely. Also assume that the integer part of our
> > numbers are equally likely to be even or odd. Then the average rounding
> > error when rounding to integers will be 0.05 if you always round up when
> > the decimal is 5. If you round towards an even number instead when the
> > decimal is 5, then you will round up half of those times, and round down
> > the other half, and the average rounding error will be 0. That's the
> > idea. Of course you could argue that it would be even more fair to make
> > the choice based on the tossing of a fair coin.

>
> That old-school rounding method you're taught is based on a wrong
> assumption of the nature of number. In the past, rounding algorithm is
> based on this:
>
> Original => (RoundUp(u|d|n), RoundNearestEven(u|d|n)
> ...
> 1.0 => 1(n), 1(n)
> 1.1 => 1(d), 1(d)
> 1.2 => 1(d), 1(d)
> 1.3 => 1(d), 1(d)
> 1.4 => 1(d), 1(d)
> 1.5 => 2(u), 2(u)
> 1.6 => 2(u), 2(u)
> 1.7 => 2(u), 2(u)
> 1.8 => 2(u), 2(u)
> 1.9 => 2(u), 2(u)
> 2.0 => 2(n), 2(n)
> 2.1 => 2(d), 2(d)
> 2.2 => 2(d), 2(d)
> 2.3 => 2(d), 2(d)
> 2.4 => 2(d), 2(d)
> 2.5 => 3(u), 2(d)
> 2.6 => 3(u), 3(u)
> 2.7 => 3(u), 3(u)
> 2.8 => 3(u), 3(u)
> 2.9 => 3(u), 3(u)
> ...
>
> In this used-to-be-thought-correct table, Round Ups algorithm have 2
> Unrounded, 8 Round Down, and 10 Round Ups which seems incorrect while
> Round Even have 2 Unrounded, 9 Round Down, and 9 Round Up which seems
> correct. The misunderstanding comes from a view that thinks that there
> is such thing as Not Rounded while in fact the only number that is Not
> Rounded is 1 and 2 while 1.0 and 2.0 must still be rounded, in
> practice we can just say that all number must be rounded somewhere.

That's not correct. If the numbers to be rounded come from a
measurement, the left column is not just a number but the representant
of an interval (as Mikael said, the're quantized). 2.3 means that the
measurement was closer to 2.3 than to 2.2 or 2.4 - that is, [2.25,
2.35) (it doesn't really matter which side is open or closed). It is
this "interval" behavior that forces the "round-to-even-on-halves"
rule.
So, the numbers 1.6-2.4 on the left column cover the interval [1.55,
2.45) and there is no doubt that they should be rounded to 2.0 because
all of them are closer to 2.0 than to any other integer. Similarly
[2.55, 3.45) are all rounded to 3.
But what to do with [2.45, 2.55), the interval represented by 2.5? We
can assume a uniform distribution here even if the whole distribution
is not (because we're talking of the smallest measurable range). So
half of the time the "true value" would have been < 2.5, and we should
round to 2. And half of the time it's > 2.5 and we should round to 3.
Rounding always to 3 introduces a certain bias in the process.
Rounding randomly (tossing a coin, by example) would be fair, but
people usually prefer more deterministic approaches. If the number of
intervals is not so small, the "round even" rule provides a way to
choose from that two possibilities with equal probability.
So when we round 2.5 we are actually rounding an interval which could
be equally be rounded to 2 or to 3, and the same for 3.5, 4.5 etc. If
the number of such intervals is big, choosing the even number helps to
make as many rounds up as rounds down.
If the number of such intervals is small, *any* apriori rule will
introduce a bias.

> > Note that if you do not have quantized values and assuming that the
> > fraction part is evenly distributed between 0 and 1, than this whole
> > argument is moot. The probability of getting exactly 0.5 is zero in that
> > case, just as the probability of getting any other specified number is zero.

>
> Another mistake, in an unquantized value the probability of getting
> exactly 0.5 (or any other number specified) is not 0 but an
> infinitesimal (i.e. lim(x) where x -> 0 (BUT NOT ZERO))

That limit IS zero. And the probability of getting exactly a certain
real number, or any finite set of real numbers, is zero too (assuming
the usual definition of probability over infinite sets). But we're not
actually talking about real numbers here.

--
Gabriel Genellina

hdante
Guest
Posts: n/a

 04-11-2008
On Apr 11, 3:33 pm, Lie <(E-Mail Removed)> wrote:
>
> That old-school rounding method you're taught is based on a wrong
> assumption of the nature of number. In the past, rounding algorithm is
> based on this:
>
> Original => (RoundUp(u|d|n), RoundNearestEven(u|d|n)
> ...
> 1.0 => 1(n), 1(n)
> 1.1 => 1(d), 1(d)
> 1.2 => 1(d), 1(d)
> 1.3 => 1(d), 1(d)
> 1.4 => 1(d), 1(d)
> 1.5 => 2(u), 2(u)
> 1.6 => 2(u), 2(u)
> 1.7 => 2(u), 2(u)
> 1.8 => 2(u), 2(u)
> 1.9 => 2(u), 2(u)
> 2.0 => 2(n), 2(n)
> 2.1 => 2(d), 2(d)
> 2.2 => 2(d), 2(d)
> 2.3 => 2(d), 2(d)
> 2.4 => 2(d), 2(d)
> 2.5 => 3(u), 2(d)
> 2.6 => 3(u), 3(u)
> 2.7 => 3(u), 3(u)
> 2.8 => 3(u), 3(u)
> 2.9 => 3(u), 3(u)
> ...
>
> In this used-to-be-thought-correct table, Round Ups algorithm have 2
> Unrounded, 8 Round Down, and 10 Round Ups which seems incorrect while
> Round Even have 2 Unrounded, 9 Round Down, and 9 Round Up which seems
> correct. The misunderstanding comes from a view that thinks that there
> is such thing as Not Rounded while in fact the only number that is Not
> Rounded is 1 and 2 while 1.0 and 2.0 must still be rounded, in
> practice we can just say that all number must be rounded somewhere.
>
> Original => (RoundUp(u|d), RoundNearestEven(u|d)
> ...
> 1.0 => 1(d), 1(d)
> 1.1 => 1(d), 1(d)
> 1.2 => 1(d), 1(d)
> 1.3 => 1(d), 1(d)
> 1.4 => 1(d), 1(d)
> 1.5 => 2(u), 2(u)
> 1.6 => 2(u), 2(u)
> 1.7 => 2(u), 2(u)
> 1.8 => 2(u), 2(u)
> 1.9 => 2(u), 2(u)
> 2.0 => 2(d), 2(d)
> 2.1 => 2(d), 2(d)
> 2.2 => 2(d), 2(d)
> 2.3 => 2(d), 2(d)
> 2.4 => 2(d), 2(d)
> 2.5 => 3(u), 2(d)
> 2.6 => 3(u), 3(u)
> 2.7 => 3(u), 3(u)
> 2.8 => 3(u), 3(u)
> 2.9 => 3(u), 3(u)
> ...
>
> In this table, we consider that a number is rounded down when the

But then, the "Round up" table gives inconsistent results if, by the
same argument, we consider 2.0 -> 2 rounding up. (you get 12 round ups
and 8 round downs just by "rethinking" the argument). So, "rounding
up" is, at the same time, better and worse than rounding to nearest
even.

> > Another side-note: My 12-year old son is now being taught to always
> > round up from mid-way between. Yet another example of the degradation of
> > maths in schools.

>
> A false assertion from a false understanding. The use of Round Up
> algorithm is a refinement of the false understanding we used to
> practice in the past.

The assertion is false, because there's no problem in rounding up,
truncating, etc. Just consider the amount of code snippets in this
thread. A simpler solution may solve a lot of problems.

Arnaud Delobelle
Guest
Posts: n/a

 04-11-2008
On Apr 11, 8:27*pm, Mark Dickinson <(E-Mail Removed)> wrote:
> On Apr 11, 2:33*pm, Lie <(E-Mail Removed)> wrote:

[...]
> > Another mistake, in an unquantized value the probability of getting
> > exactly 0.5 (or any other number specified) is not 0 but an
> > infinitesimal (i.e. lim(x) where x -> 0 (BUT NOT ZERO))

>
> I'm not sure you'll get many takers for this point of view. *If X is
> a random variable uniformly distributed on the interval [0, 1) then
> the probability that X == 0.5 is indeed exactly 0, using conventional
> definitions. *(And if you're not using conventional definitions, you
> should say so....)

And I would like to know what unconventional - but mathematically

lim x != 0
x -> 0

--
Arnaud

Lie
Guest
Posts: n/a

 04-13-2008
On Apr 12, 3:44 am, hdante <(E-Mail Removed)> wrote:
(snip)
> > In this table, we consider that a number is rounded down when the

>
> But then, the "Round up" table gives inconsistent results if, by the
> same argument, we consider 2.0 -> 2 rounding up. (you get 12 round ups
> and 8 round downs just by "rethinking" the argument). So, "rounding
> up" is, at the same time, better and worse than rounding to nearest
> even.
>

It's not round up, why? In the usual sense -- when not comparing
against round-half-even -- the number range we're talking is from x to
lim((x+1)-y)[y -> 0 from the positive side], e.g. 1 to nearly 2 (thus
the integer 2 itself is not included in the number range we're talking
since it belongs to the next set), then we choose a uniformly
distributed samples, i.e. 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8,
and 1.9. From these samples, we chose which are rounded down and which
are rounded up, it happens that 1.0 is rounded down, while 1.5 is
rounded up.

IF for the sake of argument, you choose the number range to be lim(x +
y)[y -> 0 from the positive side] to x + 1, e.g. barely above 1 to 2,
then the number sample you use is 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7,
1.8, 1.9, and 2.0, in this second number range, there are 5 round
downs (1.1, 1.2, 1.3, 1.4, 1.5) and 5 round ups (1.6, 1.7, 1.8, 1.9,
2.0), but how logical is it to choose this number range (barely above
1 to 2) against choosing the more natural range (1 to nearly 2): in
the correctly chosen number range (1 to nearly 2) all numbers in the
form of 1.x (where x is any positive number and 0) is contained within
it and there is nothing else in it, but in the second number range
(barely above 1 to 2) the number 1.0 is not included while the number
2.0 is contained in it, clearly not a clean separation of numbers in
the form of y.x where y is pre-determined and x is variable from other
possible values of y.

In short, choosing that x.0 is rounded down and x.5 is rounded up is
arbitrary but not without a reason.

Steve Holden
Guest
Posts: n/a

 04-13-2008
Lie wrote:
> On Apr 12, 3:44 am, hdante <(E-Mail Removed)> wrote:

[snip]
>
> In short, choosing that x.0 is rounded down and x.5 is rounded up is
> arbitrary but not without a reason.

Don't "arbitrary" and "not without a reason" directly contradict one
another?

regards
Steve
--
Steve Holden +1 571 484 6266 +1 800 494 3119
Holden Web LLC http://www.holdenweb.com/

Mark Dickinson
Guest
Posts: n/a

 04-13-2008
On Apr 13, 4:18*am, Lie <(E-Mail Removed)> wrote:
[...]
> it and there is nothing else in it, but in the second number range
> (barely above 1 to 2) the number 1.0 is not included while the number
> 2.0 is contained in it, clearly not a clean separation of numbers in
> the form of y.x where y is pre-determined and x is variable from other
> possible values of y.

Have you considered the fact that the real numbers of
the form 1.xxxxx... are those in the range [1.0, 2.0],
including *both* endpoints? That is, 2.0 = 1.999999...
Similarly, the midpoint of this range can be written
both in the form 1.500000... and 1.499999...

This is relevant if you think of rounding as an operation
on *decimal representations* of real numbers rather than
as an operation on real numbers themselves. I'm not sure
which point of view you're taking here.

Either way, your arguments don't change the fact that the
average rounding error is strictly positive for positive
quantized results, under round-half-away-from-zero.

Mark

andrewdied@gmail.com
Guest
Posts: n/a

 04-14-2008
On Apr 11, 4:14*am, bdsatish <(E-Mail Removed)> wrote:

> I'm interested in rounding numbers of the form "x.5" depending upon
> whether x is odd or even. Any idea about how to implement it ?

Side note: A specialized use for this is in the US Field Artillery,
where it's called "artillery expression." You don't round, but
"express" a fraction to the nearest even whole number. 2.5 is 2.0,
3.5 is 4.0, etc. Or, if you need to express to the tens, 15 is 20, 25
is 20, and so on.