Подтвердить что ты не робот

Python округляет целое число до следующих сотен

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

4b9b3361

Ответ 1

Округление обычно выполняется с номерами с плавающей запятой, и здесь есть три основные функции, которые вы должны знать: 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 до 200 до 200, например, округлить до ближайшей сотни, то встроенная функция round может сделать это для вас:

>>> int(round(130, -2))
100
>>> int(round(170, -2))
200

Ответ 2

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

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

Использование образца:

>>> roundUpToMultiple(101, 100)
200
>>> roundUpToMultiple(654, 321)
963

Ответ 3

Попробуйте следующее:

int(round(130 + 49, -2))

Ответ 4

Это поздний ответ, но есть простое решение, которое сочетает в себе лучшие аспекты существующих ответов: следующий кратный 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 - это float ( как ответ Мартина Гейслера).

>>> x = 0.1
>>> x -= x % -100
>>> x
100.0

Ответ 5

Для 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

Ответ 6

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

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

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

Ответ 7

Попробуйте следующее:

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

Ответ 8

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

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

Принимая @Martin Geisler

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 будет наиболее желанным.