Rounding a number to nearest even

Ivan Illarionov ivan.illarionov at gmail.com
Fri Apr 11 10:13:28 EDT 2008


On Apr 11, 5:49 pm, hdante <hda... at gmail.com> wrote:
> On Apr 11, 9:45 am, bdsatish <bdsat... at gmail.com> wrote:
>
>
>
> > On Apr 11, 5:33 pm, bdsatish <bdsat... at gmail.com> wrote:
>
> > > HI Gerard,
>
> > > I think you've taken it to the best possible implementation. Thanks !
> > > On Apr 11, 5:14 pm, Gerard Flanagan <grflana... at gmail.com> wrote:
>
> > > > In fact you can avoid the call to the builtin round:
>
> > > > ------------------------------------------------
>
> > > > assert myround(3.2) == 3
> > > > assert myround(3.6) == 4
> > > > assert myround(3.5) == 4
> > > > assert myround(2.5) == 2
> > > > assert myround(-0.5) == 0.0
> > > > assert myround(-1.5) == -2.0
> > > > assert myround(-1.3) == -1.0
> > > > assert myround(-1.8) == -2
> > > > assert myround(-2.5) ==  -2.0
> > > > ------------------------------------------------
>
> > OK, I was  too early to praise Gerard. The following version:
>
> > def myround(x):
> >      n = int(x)
> >      if abs(x - n) >= 0.5 and n % 2:
> >           return n + 1 - 2 * int(n<0)
> >      else:
> >           return n
>
> > of Gerard doesn't work for 0.6 (or 0.7, etc.) It gives the answer 0
> > but I would expect 1.0 ( because 0.6 doesn't end in 0.5 at all... so
> > usual rules of round( ) apply)
>
>  Interestingly, you could solve this by using python 3. :-)
>  round(x[, n])
>     Return the floating point value x rounded to n digits after the
> decimal point. If n is omitted, it defaults to zero. Values are
> rounded to the closest multiple of 10 to the power minus n; if two
> multiples are equally close, rounding is done toward the even choice
> (so, for example, both round(0.5) and round(-0.5) are 0, and
> round(1.5) is 2). Delegates to x.__round__(n).
>
>  My turn: ;-)
>
> def yaround(x):
>     i = int(x)
>     f = x - i
>     if f != 0.5 and f != -0.5: return round(x)
>     return 2.0*round(x/2.0)
>
> a = (-10.0, -9.0, -8.0, -4.6, -4.5, -4.4, -4.0, -3.6, -3.5,
>      -3.4, -0.6, -0.5, -0.4, 0.0, 0.4, 0.5, 0.6, 0.9, 1.0,
>      1.4, 1.5, 1.6, 2.0, 2.4, 2.5, 2.6, 10.0, 100.0)
>
> b = (-10.0, -9.0, -8.0, -5.0, -4.0, -4.0, -4.0, -4.0, -4.0,
>      -3.0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0,
>      1.0, 2.0, 2.0, 2.0, 2.0, 2.0, 3.0, 10.0, 100.0)
>
> for i in range(len(a)):
>     assert yaround(a[i]) == b[i]

Shorter version:
def round3k(x):
    return x % 1 != 0.5 and round(x) or round(x / 2.) * 2.


nums =  [ 0, 2, 3.2, 3.6, 3.5, 2.5, -0.5, -1.5, -1.3, -1.8, -2.5, 0.6,
0.7 ]
rnums = [ 0, 2, 3.0, 4.0, 4.0, 2.0, -0.0, -2.0, -1.0, -2.0, -2.0, 1.0,
1.0 ]

for num, rnum in zip(nums, rnums):
    assert even_round(num) == rnum, '%s != %s' % (even_round(num),
rnum)
    print num, '->', even_round(num)

It makes sense to add `from __future__ import even_round` to Python
2.6.



More information about the Python-list mailing list