tags:

views:

91

answers:

4

Hi, I have a bunch of floats and I want to round them up to the next highest multiple of 10.

For example:

10.2 should be 20
10.0 should be 10
16.7 should be 20
94.9 should be 100

I only need it to go from the range 0-100. I tried math.ceil() but that only rounds up to the nearest integer.

Thanks in advance.

+11  A: 
from math import ceil

def ceil_to_tens(x):
    return int(ceil(x / 10.0)) * 10

Edit: okay, now that I have an undeserved "Nice answer" badge for this answer, I think owe the community with a proper solution using the decimal module that does not suffer from these problems :) Thanks to Jeff for pointing this out. So, a solution using decimal works as follows:

from decimal import Decimal, ROUND_UP

def ceil_to_tens_decimal(x):
    return (Decimal(x) / 10).quantize(1, rounding=ROUND_UP) * 10

Of course the above code requires x to be an integer, a string or a Decimal object - floats won't work as that would defeat the whole purpose of using the decimal module.

It's a pity that Decimal.quantize does not work properly with numbers larger than 1, it would have saved the division-multiplication trick.

Tamás
You need to be really careful with floating point here. You think x is 10.0, but really it is 10.000...000132 and you get an answer you don't expect. You might be better off with fixed point arithmetic or Decimal.
Jeff
Thanks - your comment piqued my curiosity so I extended my answer with a variant that uses the `decimal` module.
Tamás
+3  A: 
>>> x = 16.7
>>> int( 10 * math.ceil(x/10.0))
N 1.1
+1  A: 

The answers here are fraught with peril. For example 11*1.1 - 2.1 = 10.0, right? But wait:

>>> x = 11*1.1 - 2.1
>>> int(ceil(x / 10.0)) * 10
20
>>> x
10.000000000000002
>>> 

You could try this

int(ceil(round(x, 12) / 10.0)) * 10

But choosing the number of decimal places to round to is really difficult as it is hard to predict how floating point noise accumulates. If it is really important to get this right all of the time, then you need to use fixed point arithmetic or Decimal.

Jeff
Strangely enough, `str(11*1.1-2.1)` yields `'10.0'`, which suggests another, admittedly very ugly solution: `int(ceil(float(str(x)) / 10)) * 10`.
Tamás
I believe str() rounds floats to 10 places.
Jeff
A: 

If you're looking for another solution that doesn't involve float division, here's one that uses the modulus:

def ceil_to_tens_mod(x):
    tmp = int(ceil(x))
    mod10 = tmp % 10
    return tmp - mod10 + (10 if mod10 else 0)

There's probably some way to simplify it, but there you go.

Justin Peel