Python round up integer to next hundred
Asked Answered
S

11

116

Seems that should have already been asked hundreds (pun are fun =) of times but i can only find function for rounding floats. How do I round up an integer, for example: 130 -> 200 ?

Selden answered 14/1, 2012 at 22:52 Comment(5)
Do you want 100 to be rounded up to 200 as well?Staciestack
No, Thomas' answer does just what I needSelden
Thomas' answer does round 100 up to 200. That's why I asked.Staciestack
Check the edit, I didn't pay attention to that in the first answer.Adiel
@ofko: You have accepted answer that fails with large integers; see my updated answer for details.Alvira
N
209

Rounding is typically done on floating point numbers, and here there are three basic functions you should know: round (rounds to the nearest integer), math.floor (always rounds down), and math.ceil (always rounds up).

You ask about integers and rounding up to hundreds, but we can still use math.ceil as long as your numbers smaller than 253. To use math.ceil, we just divide by 100 first, round up, and multiply with 100 afterwards:

>>> import math
>>> def roundup(x):
...     return int(math.ceil(x / 100.0)) * 100
... 
>>> roundup(100)
100
>>> roundup(101)
200

Dividing by 100 first and multiply with 100 afterwards "shifts" two decimal places to the right and left so that math.ceil works on the hundreds. You could use 10**n instead of 100 if you want to round to tens (n = 1), thousands (n = 3), etc.

An alternative way to do this is to avoid floating point numbers (they have limited precision) and instead use integers only. Integers have arbitrary precision in Python, so this lets you round numbers of any size. The rule for rounding is simple: find the remainder after division with 100, and add 100 minus this remainder if it's non-zero:

>>> def roundup(x):
...     return x if x % 100 == 0 else x + 100 - x % 100

This works for numbers of any size:

>>> roundup(100)
100
>>> roundup(130)
200
>>> roundup(1234567891234567891)
1234567891234567900L

I did a mini-benchmark of the two solutions:

$ python -m timeit -s 'import math' -s 'x = 130' 'int(math.ceil(x/100.0)) * 100'
1000000 loops, best of 3: 0.364 usec per loop
$ python -m timeit -s 'x = 130' 'x if x % 100 == 0 else x + 100 - x % 100'
10000000 loops, best of 3: 0.162 usec per loop

The pure integer solution is faster by a factor of two compared to the math.ceil solution.

Thomas proposed an integer based solution that is identical to the one I have above, except that it uses a trick by multiplying Boolean values. It is interesting to see that there is no speed advantage of writing the code this way:

$ python -m timeit -s 'x = 130' 'x + 100*(x%100>0) - x%100'
10000000 loops, best of 3: 0.167 usec per loop

As a final remark, let me also note, that if you had wanted to round 101–149 to 100 and round 150–199 to 200, e.g., round to the nearest hundred, then the built-in round function can do that for you:

>>> int(round(130, -2))
100
>>> int(round(170, -2))
200
Nystatin answered 14/1, 2012 at 23:7 Comment(9)
I'm not doing a normal rounding here, if I were yes, I would use round()Selden
@ofko: right, you want to round up. The math.ceil is the canonical way to do that — dividing and multiplying by 100 is the canonical way to make round, ceil, and floor work on hundreds.Nystatin
After the recent edits, it now makes sense to accept this answer.Selden
-1 This approach may be "canonical" with floats, but it FAILS with large integers. See my answer for details. The OP specifically asked for integers and expressed no upper bound on the size of numbers.Alvira
@JohnMachin: The downvote is for questions that "are not useful" and I fail to see why this simple and straight-forward answer is not useful. Infact, the OP marked it as accepted, so it is useful. Further, when someone needs help to round 130 to 200, then I think it's stretching it a bit to complain about not rounding 1234567891234567891 correctly. You're right that there's limited precission in float compared to long (of course!), but for most practical situations a float is plenty big.Nystatin
One can reliably infer nothing from acceptance of an answer. One can reliably infer nothing from a single example input value. The question did ask for integers, not floats. Your answer still leads off with floats and contains the "canonical" waffle. Your new integer only solution is at least correct but is baroque and slow.Alvira
@JohnMachin: you really take offense to me calling math.ceil the canonical way to round up, don't you? I've taken it out now and I hope you like the introduction better.Nystatin
You need to look up "take offence". I have not taken offence. I am not offended. My point is that "canonical" merely means "recommended by some prescribing authority" or "usual"; it doesn't automatically mean "good idea". New introduction: (1) it STILL starts off with floats! (2) round does not round to the nearest integer; it rounds to the nearest integral multiple of 10 ** (-second_arg); the behaviour of round() changed between 2.X and 3.X; round should be mentioned in this context only to warn against its use.Alvira
@JohnMachin: Okay, I'm glad you're not offended. I was not aware of the change to round in Python 3, thanks for pointing that out. I mention math.ceil and round since I feel that they are the first two functions you should think of them you're asked to round something. I'm trying to give the OP building blocks so that he can solve rounding tasks in the future.Nystatin
H
44

This is a late answer, but there's a simple solution that combines the best aspects of the existing answers: the next multiple of 100 up from x is x - x % -100 (or if you prefer, x + (-x) % 100).

>>> x = 130
>>> x -= x % -100  # Round x up to next multiple of 100.
>>> x
200

This is fast and simple, gives correct results for any integer x (like John Machin's answer) and also gives reasonable-ish results (modulo the usual caveats about floating-point representation) if x is a float (like Martin Geisler's answer).

>>> x = 0.1
>>> x -= x % -100
>>> x
100.0
Hypophosphate answered 30/12, 2012 at 17:18 Comment(2)
your solution is as as fast as Martin's but notation is shorter. thanks. %timeit 'x = 110' 'x -= x % -100' # 100000000 loops, best of 3: 9.37 ns per loop VS %timeit 'x = 110' 'x + 100*(x%100>0) - x%100' #100000000 loops, best of 3: 9.38 ns per loopEmee
Note: To always round down, it is x -= x % +100Upside
B
25

Try this:

int(round(130 + 49, -2))
Boudicca answered 14/1, 2012 at 22:54 Comment(3)
why int() ? type(round(999,-2)) is int (python 3.8)Viridian
This doesn't always round up though, which is what the question asked.Salesperson
This rounds 1 down to 0 instead of up to 100.Sadie
S
19

Here's a general way of rounding up to the nearest multiple of any positive integer:

def roundUpToMultiple(number, multiple):
    num = number + (multiple - 1)
    return num - (num % multiple)

Sample usage:

>>> roundUpToMultiple(101, 100)
200
>>> roundUpToMultiple(654, 321)
963
Sourdough answered 14/1, 2012 at 23:23 Comment(1)
equivalent, shorter method: lambda number, multiple: multiple * (1 + (number - 1) // multiple)Frown
A
8

For a non-negative, b positive, both integers:

>>> rup = lambda a, b: (a + b - 1) // b * b
>>> [(x, rup(x, 100)) for x in (199, 200, 201)]
[(199, 200), (200, 200), (201, 300)]

Update The currently-accepted answer falls apart with integers such that float(x) / float(y) can't be accurately represented as a float. See this code:

import math

def geisler(x, y): return int(math.ceil(x / float(y))) * y

def orozco(x, y): return x + y * (x % y > 0) - x % y

def machin(x, y): return (x + y - 1) // y * y

for m, n in (
    (123456789123456789, 100),
    (1234567891234567891, 100),
    (12345678912345678912, 100),
    ):
    print; print m, "m"; print n, "n"
    for func in (geissler, orozco, machin):
        print func(m, n), func.__name__

Output:

123456789123456789 m
100 n
123456789123456800 geisler
123456789123456800 orozco
123456789123456800 machin

1234567891234567891 m
100 n
1234567891234568000 geisler <<<=== wrong
1234567891234567900 orozco
1234567891234567900 machin

12345678912345678912 m
100 n
12345678912345680000 geisler <<<=== wrong
12345678912345679000 orozco
12345678912345679000 machin

And here are some timings:

>\python27\python -m timeit -s "import math;x =130" "int(math.ceil(x/100.0))*100"
1000000 loops, best of 3: 0.342 usec per loop

>\python27\python -m timeit -s "x = 130" "x + 100 * (x % 100 > 0) - x % 100"
10000000 loops, best of 3: 0.151 usec per loop

>\python27\python -m timeit -s "x = 100" "(x + 99) // 100 * 100"
10000000 loops, best of 3: 0.0903 usec per loop
Alvira answered 14/1, 2012 at 23:49 Comment(1)
I know the OP was about rounding an integer - but I wanted to point out that you would try to use those 3 options on (0.5,10) which I would expect to return 10 then the first two methods (geisler & orozco) return 10 as expected while machin returns 0Jar
P
5

Try this:

import math

def ceilm(number, multiple):
    '''Returns a float rounded up by a factor of the multiple specified'''
    return math.ceil(float(number)/multiple) * multiple

Sample usage:

>>> ceilm(257, 5)
260
>>> ceilm(260, 5)
260
Podiatry answered 24/11, 2015 at 5:15 Comment(0)
A
3

If your int is x: x + 100 - x % 100

However, as pointed in comments, this will return 200 if x==100.

If this is not the expected behavior, you can use x + 100*(x%100>0) - x%100

Adiel answered 14/1, 2012 at 22:55 Comment(6)
You might want to use the other solutions if you don't like magic numbers though. If you're concerned with performance, this however runs faster.Adiel
Yes, 100 should remain not be rounded up but if that would make the formula too complicated, I can prevent that using code, no bigySelden
Well the other version solves this, as it includes the check before adding 100! If this adresses your need, don't forget to accept! :)Adiel
I'm sorry, but I find this code very un-pythonic. Yes, a bool has a numeric value, so yes, you can multiply with a boolean expression. But the other solutions are clearer.Nystatin
Well, I indeed pointed out that other code could be preferred if performance is not a key parameter.Adiel
@ThomasOrozco: you're right, your solution is twice as fast at the one I proposed.Nystatin
J
3

Warning: Premature optimizations ahead...

Since so many of the answers here do the timing of this I wanted to add another alternative.

Taking @Martin Geisler 's

def roundup(x):
    return x if x % 100 == 0 else x + 100 - x % 100

(which i like best for several reasons)

but factoring out the % action

def roundup2(x):
    x100= x % 100
    return x if x100 == 0 else x + 100 - x100

Yields a ~20% speed improvement over the original

def roundup3(x):
    x100 = x % 100
    return x if not x100 else x + 100 - x100

Is even better and is ~36% faster then the original

finally I was thinking that I could drop the not operator and change the order of the branches hoping that this would also increase speed but was baffled to find out that it is actually slower dropping back to be only 23% faster then the original.

def roundup4(x):
    x100 = x % 100
    return x + 100 - x100  if x100 else x


>python -m timeit -s "x = 130" "x if x % 100 == 0 else x + 100 - x % 100"
1000000 loops, best of 3: 0.359 usec per loop

>python -m timeit -s "x = 130" "x100 = x % 100"  "x if x100 == 0 else x + 100 - x100"
1000000 loops, best of 3: 0.287 usec per loop

>python -m timeit -s "x = 130" "x100 = x % 100"  "x if not x100 else x + 100 - x100"
1000000 loops, best of 3: 0.23 usec per loop

>python -m timeit -s "x = 130" "x100 = x % 100"  "x + 100 - x100 if x100 else x"
1000000 loops, best of 3: 0.277 usec per loop

explanations as to why 3 is faster then 4 would be most welcome.

Jar answered 3/10, 2017 at 10:40 Comment(0)
T
1

Here is a very simple solution:

next_hundred = x//100*100+100

How does it work?

  1. Perform the integer division by 100 (it basically cuts off the fractional part of the normal division). In this way you obtain the tens of a number. For example: 243//100=2.
  2. Multiply by 100, getting the original number without its tens and ones. For example: 2*100=200.
  3. Add 100 to get the desired result. For example: 200+100=300

Some examples

  • 0...99 rounded to 100
  • 100...199 rounded to 200
  • etc.

A slightly modified approach rounds 1...100 to 100, 101...200 to 200, etc.:

next_hundred = (x-1)//100*100+100
Tropo answered 28/12, 2019 at 13:14 Comment(0)
R
1

Simply:

round(599, -2)

will give:

600

Rosemari answered 18/5, 2021 at 7:19 Comment(1)
This fails even for the example in the question (130 -> 200).Echeverria
S
0
n // -100 * -100

(It's like // 100 * 100, which floors, but temporarily negating turns the world upside down so it ceils instead.)

Sadie answered 1/2, 2024 at 18:33 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.