Python округляет целое число до следующей сотни - PullRequest
64 голосов
/ 15 января 2012

Кажется, это уже сто раз задавали (каламбур весело =), но я могу найти только функцию для округления поплавков. Как округлить целое число, например: 130 -> 200?

Ответы [ 8 ]

114 голосов
/ 15 января 2012

Округление обычно выполняется для чисел с плавающей запятой, и здесь есть три основные функции, которые вы должны знать: round (округление до ближайшего целого числа), math.floor (всегда округляется в меньшую сторону) и math.ceil (всегда округляется в большую сторону).

Вы спрашиваете о целых числах и округляете до сотен, но мы все равно можем использовать math.ceil, пока ваши числаменьше чем 2 53 .Чтобы использовать math.ceil, мы просто делим сначала на 100, округляем вверх и умножаем на 100 потом:

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

Сначала делим на 100 и затем умножаем на 100, сдвигая два знака после запятой вправо иосталось так, что math.ceil работает на сотни.Вы можете использовать 10**n вместо 100, если хотите округлить до десятков (n = 1), тысяч (n = 3) и т. Д.

Альтернативный способ сделать это - избежать чисел с плавающей запятой (они имеют ограниченную точность) и вместо этого используют только целые числа.Целые числа имеют произвольную точность в Python, так что это позволяет округлять числа любого размера.Правило округления простое: найдите остаток после деления с 100 и добавьте 100 минус этот остаток, если он не равен нулю:

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

Это работает для чисел любого размера:

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

Я выполнил мини-тестирование двух решений:

$ 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

Чистое целочисленное решение быстрее в два раза по сравнению с решением math.ceil.

Томас предложил целочисленное решение, идентичное тому, которое у меня было выше, за исключением того, что оно использует хитрость путем умножения логических значений.Интересно заметить, что при написании кода таким способом нет преимущества в скорости:

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

В качестве последнего замечания позвольте мне также отметить, что если вы хотели округлить 101–149 до 100 иокругление 150–199 до 200, например, округление до ближайшего ста, тогда встроенная функция round может сделать это для вас:

>>> int(round(130, -2))
100
>>> int(round(170, -2))
200
19 голосов
/ 15 января 2012

Попробуйте это:

int(round(130 + 49, -2))
18 голосов
/ 30 декабря 2012

Это поздний ответ, но есть простое решение, в котором сочетаются лучшие аспекты существующих ответов: следующий кратный 100 по сравнению с x равен x - x % -100 (или, если вы предпочитаете, x + (-x) % 100).

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

Это быстро и просто, дает правильные результаты для любого целого числа x (как ответ Джона Мачина), а также дает разумные результаты (по модулю обычных предупреждений о представлении с плавающей запятой), еслиx - это число с плавающей точкой (как ответ Мартина Гейслера).

>>> x = 0.1
>>> x -= x % -100
>>> x
100.0
17 голосов
/ 15 января 2012

Вот общий способ округления до ближайшего кратного любого положительного целого числа:

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

Пример использования:

>>> roundUpToMultiple(101, 100)
200
>>> roundUpToMultiple(654, 321)
963
9 голосов
/ 15 января 2012

Для a неотрицательный, b положительный, оба целых числа:

>>> 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)]

Обновление Принятый в настоящее время ответ распадается с целыми числамитакой, что float (x) / float (y) не может быть точно представлен как float.См. Этот код:

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__

Вывод:

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

А вот некоторые моменты времени:

>\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
3 голосов
/ 03 октября 2017

Предупреждение: впереди преждевременная оптимизация ...

Так как многие ответы здесь приводятся во времени, я хотел добавить еще одну альтернативу.

Принимая @Martin Geisler's

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

(что мне нравится больше всего по нескольким причинам)

, но с учетом действия%

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

Дает ~ 20% -ное улучшение скорости по сравнению с исходным

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

Еще лучше и на ~ 36% быстрее, чем исходный

, наконец, я подумал, что могу опустить оператор not и изменить порядок ветвей, надеясь, что это также увеличитскорость, но был сбит с толку, обнаружив, что на самом деле он медленнее отбрасывает назад, чтобы быть только на 23% быстрее, чем оригинал.

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

объяснения, почему 3 быстрее, чем 4, было бы очень желательно.

3 голосов
/ 15 января 2012

Если ваш int равен x: x + 100 - x % 100

Однако, как указано в комментариях, будет возвращено 200, если x==100.

Если это не ожидаемое поведение, вы можете использовать x + 100*(x%100>0) - x%100

2 голосов
/ 24 ноября 2015

Попробуйте:

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

Пример использования:

>>> ceilm(257,5)
260
>>> ceilm(260,5)
260
...