views:

437

answers:

5

Is there a build-in function that can round like this:

10 -> 10
12 -> 10
13 -> 15
14 -> 15
16 -> 15
18 -> 20
+19  A: 

I don't know of a standard function in Python, but this works for me:

def myround(x, base=5):
    return int(base * round(float(x)/base))

It is easy to see why the above works. You want to make sure that your number divided by 5 is an integer, correctly rounded. So, we first do exactly that (round(float(x)/5)), and then since we divided by 5, we multiply by 5 as well. The final conversion to int is because round() returns a floating-point value in Python.

I made the function more generic by giving it a base parameter, defaulting to 5.

Alok
+1 nice :) ----
Felix Kling
I think it would look better with: `int(base * round(float(x)/base))` instead of the `1.0*x` which feels a bit kludgy.
Olivier
I agree. Thanks for the comment. I changed it.
Alok
+4  A: 

It's just a matter of scaling

>>> a=[10,11,12,13,14,15,16,17,18,19,20]
>>> for b in a:
...     int(round(b/5.0)*5.0)
... 
10
10
10
15
15
15
15
15
20
20
20
amo-ej1
I'd wrap the round() in an int() - then you get the answers the OP asked for...
Matthew Schinckel
Agree, I updated my comment
amo-ej1
+1  A: 

round(x[, n]): values are rounded to the closest multiple of 10 to the power minus n. So if n is negative...

def round5(x):
    return int(round(x*2, -1)) / 2

Since 10 = 5 * 2, you can use integer division and multiplication with 2, rather than float division and multiplication with 5.0. Not that that matters much, unless you like bit shifting

def round5(x):
    return int(round(x << 1, -1)) >> 1
pwdyson
+1 for showing us that round() can handle rounding to multiples other than 1.0, including higher values. (Note, however, that the bit-shifting approach won't work with floats, not to mention it's much less readable to most programmers.)
Peter Hansen
@Peter Hansen thanks for the +1. Need to have an int(x) for the bit shifting to work with floats. Agreed not the most readable and I wouldn't use it myself, but I did like the "purity" of it only involving 1's and not 2's or 5's.
pwdyson
A: 

What about this:

 def divround(value, step):
     return divmod(value, step)[0] * step
Christian Hausknecht
Damn, this was not the question... but I modifed it (see modified version!).
Christian Hausknecht
+1  A: 

Modified version of divround :-)

def divround(value, step, barrage):
    result, rest = divmod(value, step)
    return result*step if rest < barrage else (result+1)*step
Christian Hausknecht
so in this case you use divround(value, 5, 3)? or maybe divround(value, 5, 2.5)?
pwdyson
divround(value, 5, 3), exactly.
Christian Hausknecht