Як округлити число в Python?


486

Ця проблема мене вбиває. Як відбувається одне зіставлення числа UP в Python?

Я спробував раунд (число), але це округлення числа вниз. Приклад:

round(2.3) = 2.0 and not 3, what I would like

Я спробував int (число + .5), але це знову закруглює число! Приклад:

int(2.3 + .5) = 2

Потім я спробував круглий (число + .5), але це не вийде у кращих випадках. Приклад:

WAIT! THIS WORKED!

Порадьте, будь ласка.


4
round(number + .5)не працює, якщо число є цілим числом. round(3+.5) == 4, коли ти насправді хочеш 3.
Неару

Відповіді:


845

Функція стелі (стеля):

import math
print(math.ceil(4.2))

21
Розробка: math.ceil повертає найменше ціле число, яке більше або дорівнює вхідному значенню. Ця функція розглядає вхід як поплавок (Python не має сильно типізованих змінних), і функція повертає поплавок. Якщо ви хочете int, ви можете сконструювати int з повернутого значення, тобтоint(math.ceil(363))
RW Sinnet

9
@Sinnet: Насправді можна сказати, що python сильно набрав stackoverflow.com/a/11328980/5069869
Bernhard

1
@TheEspinosa: Так, python, безумовно, сильно набраний. Просто багато функцій задають питання про тип деяких параметрів і виконують різний код залежно від відповіді.
quamrana

12
@RWSinnet У Python 3 math.ceilповертає фактичний цілий об'єкт, а не просто плаваючий об'єкт із цілим значенням.
Артур Такка

Подбайте про флоят точності з - за 10000000 * 0.00136 = 13600.000000000002стеля може збільшити багатоmath.ceil(10000000 * 0.00136) = 13601.0
ofthestreet

170

Я знаю, що ця відповідь - це питання, яке час від часу повертається, але якщо ви не хочете імпортувати математику і просто хочете округлити, це працює для мене.

>>> int(21 / 5)
4
>>> int(21 / 5) + (21 % 5 > 0)
5

Перша частина стає 4, а друга частина оцінюється як "True", якщо є залишок, який на додаток True = 1; False = 0. Отже, якщо немає залишку, він залишається тим самим цілим, але якщо є залишок, він додає 1.


38
Приємно. Ви також можете використовувати //для цілого поділу, так це стає 21 // 5 + (21 % 5 > 0).
naught101

6
Це найкраще рішення, якщо задіяні лише цілі числа. Без зайвих floats. Приємно.
Ніко Шльомер

158

Цікава проблема Python 2.x, яку потрібно пам’ятати:

>>> import math
>>> math.ceil(4500/1000)
4.0
>>> math.ceil(4500/1000.0)
5.0

Проблема полягає в тому, що розділення двох int в python виробляє ще один int, і це усікається перед викликом на стелі. Ви повинні зробити одне значення float (або литий), щоб отримати правильний результат.

У JavaScript точно такий же код дає інший результат:

console.log(Math.ceil(4500/1000));
5

44
У Python 2.x : int / int -> int та int / float -> float У Python 3.x : int / int може призвести до float
gecco

7
ви можете отримати Python 3.x щодо поведінки на певних версіях Python 2.x, включивши "справжній поділ", як показано тут
Rob Dennis

110

Якщо ви працюєте з цілими числами, одним із способів округлення є скористатися тим, що //округлюється вниз: Просто виконайте ділення на від’ємне число, а потім скасуйте відповідь. Ні імпорт, плаваюча точка, ні умовні умови не потрібні.

rounded_up = -(-numerator // denominator)

Наприклад:

>>> print(-(-101 // 5))
21

1
А як бути, коли вам не потрібно виконувати жодної математичної операції? Тобто у вас просто один номер.
Клік

2
@Klik: тоді ви можете просто розділити на 1 ==> - (-num // 1), і ви отримуєте свою відповідь :-) Приємного дня! Девід Бау: дуже приємна пропозиція!
Марко smdm

10
Я присвятив усі відповіді тут, і це було в п’ять разів швидше, ніж наступне найкраще (math.ceil). @Andreas мав той самий час
міні тонт

@minitotent Це не дивно, оскільки це просте ціле ділення і пара операцій на один цикл. Це така відповідь, яка дає вам роботу: розуміння не лише мови, але й усіх шарів абстракцій під нею.
Неаро

Приємно! Я завжди використовував (num + den - 1) // den, що добре для intвведення позитивних знаменників, але не вдається, якщо навіть один неінтеграл floatзадіяний (чисельник, чи знаменник); це більш магічно виглядає, але працює як для ints, так і для floats. Для маленьких чисельників це також швидше (на CPython 3.7.2), хоча як не дивно, коли лише чисельник досить великий, що потрібна математика на основі масиву, ваш підхід повільніше; Не зрозуміло, чому це так, оскільки робота ділення повинна бути подібною, і два одинарні заперечення повинні бути дешевшими, ніж додавання + віднімання.
ShadowRanger

56

Можливо, вам також сподобається numpy:

>>> import numpy as np
>>> np.ceil(2.3)
3.0

Я не кажу, що це краще, ніж математика, але якщо ви вже використовували numpy для інших цілей, ви можете зберігати код.

У всякому разі, просто деталь, на яку я натрапив. Я багато вживаю нуме і був здивований, що його не згадували, але, звичайно, прийнята відповідь працює чудово.


3
Використання numpy теж приємно. Найпростіше було б з математикою, оскільки це вже частина вбудованого python у бібліотеках. Це має більше сенсу. Замість цього, як ви вже згадували, якщо ви використовуєте багато нуме для інших питань, то має сенс і послідовно використовувати numpy.ceil :-) Добрий підказку!
Марко smdm

30

Використовуйтеmath.ceil для округлення:

>>> import math
>>> math.ceil(5.4)
6.0

ПРИМІТКА . Вхід повинен бути плаваючим.

Якщо вам потрібно ціле число, зателефонуйте, intщоб перетворити його:

>>> int(math.ceil(5.4))
6

BTW, використовуйте math.floorдля округлення вниз і roundдля округлення до найближчого цілого числа.

>>> math.floor(4.4), math.floor(4.5), math.floor(5.4), math.floor(5.5)
(4.0, 4.0, 5.0, 5.0)
>>> round(4.4), round(4.5), round(5.4), round(5.5)
(4.0, 5.0, 5.0, 6.0)
>>> math.ceil(4.4), math.ceil(4.5), math.ceil(5.4), math.ceil(5.5)
(5.0, 5.0, 6.0, 6.0)

1
Вхід не обов'язково повинен бути плаваючим, якщо використовується python 3: ceil() подбає про нього внутрішньо
guival


11

Я здивований, що ніхто не запропонував

(numerator + denominator - 1) // denominator

для цілого поділу з округленням. Раніше це звичайний спосіб для C / C ++ / CUDA (див. divup)


2
Релевантно лише для мов, які набираються статично. Якщо знаменником є ​​поплавок, ви мертві.
Bharel

Це також працює лише послідовно, якщо знаменник є позитивним; якщо знаменник від'ємний, 1замість віднімання його потрібно додати , або перегорнути знаки чисельника та знаменника перед виконанням математики.
ShadowRanger

7

Будьте чіткими, округлене значення має бути плаваючою

a = 8 
b = 21
print math.ceil(a / b)
>>> 0

але

print math.ceil(float(a) / b)
>>> 1.0

6

Спробуйте це:

a = 211.0
print(int(a) + ((int(a) - a) != 0))

1
Розумний. У ((int(a) - a) != 0)вираз повертається 1щоразу , коли aповинен бути округляється. Ви можете розширити свою відповідь і пояснити, як це працює.
Том Аранда

@TomAranda Чи може хто-небудь пояснити, як булевий вираз оцінює значення, будь ласка?
Боуен Лю

6
>>> def roundup(number):
...     return round(number+.5)
>>> roundup(2.3)
3
>>> roundup(19.00000000001)
20

Ця функція не потребує модулів.


Що робити, якщо ваш номер 3, то він би 4
завершився, до

15
Це працює лише у 99% усіх випадків. Ви не продумали це належним чином. Таких рішень слід уникати будь-якою ціною.
Неару

тому замість +5 робити + .49999999 досить добре для мене.
FlyingZebra1

5

Наведені вище відповіді правильні, однак імпорт mathмодуля саме для цієї функції зазвичай для мене є трохи надмірним. На щастя, є ще один спосіб зробити це:

g = 7/5
g = int(g) + (not g.is_integer())

Trueі Falseінтерпретуються як 1і 0в заяві, що включає числа в python. g.is_interger()в основному перекладається на g.has_no_decimal()або g == int(g). Так читається остання заява англійською мовою round g down and add one if g has decimal.


1
І якщо ви відчуваєте фантазію, можете скористатися int(g) + (g % 1 > 0)натомість ;-)
Nearoo

from math import ceilздається, виправлено імпорт всього математичного модуля :)
SH7890

@ SH7890 Боюся, що ця лінія не сильно відрізняється з import mathточки зору того, що відбувається за лаштунками. Він просто скидає всі символи, крім ceil.
Неару

5

Без імпорту математики // з використанням базового оточення:

а) метод / метод класу

def ceil(fl): 
  return int(fl) + (1 if fl-int(fl) else 0)

def ceil(self, fl): 
  return int(fl) + (1 if fl-int(fl) else 0)

б) лямбда:

ceil = lambda fl:int(fl)+(1 if fl-int(fl) else 0)

5

Для тих, хто хоче округлити a / bі отримати ціле число:

Інший варіант використання цілочисельного поділу - це

def int_ceil(a, b):
    return (a - 1) // b + 1

>>> int_ceil(19, 5)
4
>>> int_ceil(20, 5)
4
>>> int_ceil(21, 5)
5

3

У випадку, якщо хтось хоче закруглити певний знак після коми:

import math
def round_up(n, decimals=0):
    multiplier = 10 ** decimals
    return math.ceil(n * multiplier) / multiplier

1

Я здивований, що ще не бачив цієї відповіді round(x + 0.4999), тому збираюся її відкласти. Зауважте, що це працює з будь-якою версією Python. Зміни, внесені в схему округлення Python, ускладнили ситуацію. Дивіться цю публікацію .

Без імпорту я використовую:

def roundUp(num):
    return round(num + 0.49)

testCases = list(x*0.1 for x in range(0, 50))

print(testCases)
for test in testCases:
    print("{:5.2f}  -> {:5.2f}".format(test, roundUp(test)))

Чому це працює

Від док

Для вбудованих типів, що підтримують round (), значення округляються до найближчого кратного 10 до потужності мінус n; якщо два кратні однаково близькі, проводиться округлення до рівномірного вибору

Тому 2,5 округляється до 2, а 3,5 округляється до 4. Якщо це не було, то округлення можна зробити, додавши 0,5, але ми хочемо уникнути попадання до точки на півдорозі. Отже, якщо ви додасте 0,4999, ви наблизитеся, але з достатньою маржею, щоб бути округленою до того, що ви зазвичай очікували. Звичайно, це не вдасться, якщо x + 0.4999дорівнює [n].5000, але це малоймовірно.


2
Використовуючи 0.4999, він не зможе дати правильний результат для будь-якого вводу між ???. 0000 та ???. 0001 (відкритий інтервал), а не просто ??? 0001. Наприклад, якщо ви спробуєте його з 3.00005, ви отримаєте результат 3 замість очікуваного 4. Звичайно, ви можете зменшити ймовірність цього, додавши все більше та більше цифр до максимальної точності поплавків, але що таке вкажіть, що якщо під рукою є більш надійні та інтуїтивні рішення, як, наприклад, використання math.ceil()?
blubberdiblub

@blubberdiblub У своїй відповіді я заявляю Without importing I use:. Я також згадував, що він не вийде, якщо значення x + 0.4999дорівнює [n].5000.
Клік

4
Так, ви заявляєте у своїй відповіді, що ваше рішення не імпортується, але я не бачу його значення. mathМодуль і math.ceil()знаходиться в стандартній бібліотеці, тому скрізь для всіх практичних цілей без установки додаткових речей. Щодо вашої згадки про те, коли вона не вдається, це не є повною у вашій відповіді, оскільки не вдається протягом цілого інтервалу, а не лише для однієї точки. З технічної точки зору ви можете стверджувати, що ви правильні, як ви кажете, якщо ви не iff , але це зробить враження на випадкового читача, що це менш ймовірно, ніж насправді.
blubberdiblub

0

Щоб зробити це без будь-якого імпорту:

>>> round_up = lambda num: int(num + 1) if int(num) != num else int(num)
>>> round_up(2.0)
2
>>> round_up(2.1)
3

0

Я знаю, що це вже досить давно, але я знайшов досить цікаву відповідь, тож ось:

-round(-x-0.5)

Це виправляє регістри ребер і працює як для позитивних, так і для від’ємних чисел, і не вимагає імпорту функції

Ура


2
Це все одно завершиться вниз-round(-x-0.3) = x
Diblo Dk

0

коли ви керуєте 4500/1000 в python, результат буде 4, тому що для типового python як цілий результат вважаємо, що логічно: 4500/1000 = 4.5 -> int (4.5) = 4, а ceil з 4 очевидно - 4

використовуючи 4500 / 1000.0, результат буде 4,5, а перекриття 4,5 -> 5

Використовуючи javascript, ви отримаєте 4,5 в результаті 4500/1000, тому що javascript отримує лише результат як "числовий тип" і повертає результат безпосередньо як float

Щасти!!


Це справедливо лише в Python 2.x. У Python 3 ділення з одиничним /завжди призводить до поплавця, тому 4500/1000завжди є 4.5.
Неару

0

Якщо ви не хочете нічого імпортувати, ви завжди можете написати власну просту функцію як:

def RoundUP(num): if num== int(num): return num return int(num + 1)


2
Це не працює, якщо число 2,05. У вас має бути принаймні стільки цифр із знаком 9, скільки вхід, і ви отримаєте 0,999 ... що є 1. Але тоді ваш кутовий корпус 2 знову закруглюється вгору. - Ну, мабуть, є причина, чому math.ceil є.
Йоханнес Марія Франк

-1

Ви можете використовувати підлоговий пристрій і додати до нього 1. 2.3 // 2 + 1


2
або використовувати ceil()замість того, щоб дивно робити навпаки, а потім компенсувати
відгадку

2
Це не спрацює. Наприклад:from math import ceil; assert 4 // 2 + 1 == ceil(4 / 2)
Карл Томе

-1

Я думаю, ви заплутаєте робочі механізми між int()і round().

int()завжди скорочує десяткові числа, якщо вказано плаваюче число; тоді як round(), у випадку, 2.5коли 2і 3обидва знаходяться на однаковій відстані від 2.5, Python повертається в залежності від точки, що більше 0.

round(2.5) = 3
int(2.5) = 2

"округлення" означає, що, наприклад, 2.3перетворюється 3, що відбувається ні в одному з ваших прикладів.
Неару

-2

Моя частка

Я перевірив print(-(-101 // 5)) = 21наведений приклад вище.

Тепер для округлення:

101 * 19% = 19.19

Я не можу використовувати, **тому я помножую множення на ділення:

(-(-101 //(1/0.19))) = 20

-3

Я в основному початківець в Python, але якщо ви просто намагаєтеся округлитись, а не вниз, чому б не зробити:

round(integer) + 1

2
Це не працюватиме для жодного цілого числа i, де 2,5 <ціле число <3. Бажане значення після округлення дорівнює 3, але ваш вираз перетворить його на 4.
Пранав Шукла,

1
Я думаю, ти маєш на увазі round(integer + 0.5)Це те, що я часто роблю
Клік
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.