Чому операції math.ceil () та math.floor () Python повертають плавці замість цілих чисел?


170

Може хтось пояснить це (прямо з документів - моє наголос):

math.ceil (x) Повертає стелю x у вигляді поплавця , найменше ціле значення більше або дорівнює x.

math.floor (x) Повернути підлогу x у вигляді поплавця , найбільше ціле значення менше або рівне x.

Чому б .ceilі .floorповертати плавці, коли вони за визначенням повинні обчислювати цілі числа?


Редагувати:

Ну це має дуже хороші аргументи, чому вони повинні повертатися поплавці, і я просто звикнути до ідеї, коли @jcollado зазначив, що вони насправді роблять повернення розр в Python 3 ...


1
Я гадаю, що це тому, що x - це плаваюче, а не ціле число, але оскільки я не знаю і не використовую Python, я дозволю комусь іншому відповісти більш остаточно. :)
Адам V

6
@ Адам, але вся суть операцій під стелею / підлогою полягає в тому, щоб круглі плавали до цілих чисел!
Ярін

1
Це також роздратувало мене в перший раз, коли я натрапив на це, тому що це просто здається неправильним. Принаймні, це не надто важко у використанні int(floor(n)).
Вім

1
За іронією долі (оскільки поплавці використовувались для запобігання переливів), значення, повернене підлогою / стелею, є безглуздим у малих цифрах через представлення поплавця, задовго до того, як 64 біт int переповниться. [Це не було правдою за старих 32-х біт.]
Ів Дауст

Відповіді:


99

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

Поміркуйте: Якщо floor()повернене ціле число, що має floor(1.0e30)повернутись?

Хоча цілі числа Python тепер довільної точності, це було не завжди так. Стандартні функції бібліотеки - це тонкі обгортки навколо еквівалентних функцій бібліотеки С.


13
І хоча цілі числа Python тепер є довільною точністю, все ще є поплавці, підлога і стеля яких не можуть бути представлені цілими числами. Спробуйте floor(float("inf"))або ceil(float("nan")).
Майкл Гофман

4
@ Michael- Мабуть, у P3 тепер ви отримаєте OverflowExceptions, якщо ви спробуєте це. Див jcollado відповідь «s
Ярина

4
Е, він повинен повернути тип "long" (він же "bigint"), чи не так? Здається, явна відповідь для мене, але зараз я відчуваю, що я якось наївний.
koschei

3
@koschei: Це в Python 3.x, див. відповідь jcollado.
Грег Хьюгілл

Дивіться також коментар до іншої відповіді, чому це має сенс навіть для номерів, які знаходяться в діапазоні.
ivan_pozdeev

96

Як вказують інші відповіді, у python вони повертаються плаваючими, ймовірно, з історичних причин для запобігання проблем із переповненням. Однак вони повертають цілі числа в python 3.

>>> import math
>>> type(math.floor(3.1))
<class 'int'>
>>> type(math.ceil(3.1))
<class 'int'>

Додаткову інформацію можна знайти в PEP 3141 .


@ jcollado- Де ви бачите, що вони повертають цілі числа в P3?
Ярін

4
@Yarin Я просто набрав команди вище. Також якщо ви спробуєте з float("inf")або float("nan"), ви отримаєте OverflowErrorвиняток.
jcollado

10
Для повноти плавання Python's numpy.floorі ceilreturn (<class 'numpy.float64'>)
Neil G

1
@jcollado: float("inf")не створює винятку в Python 2.7 або 3
endolith

1
@endolith Ти маєш рацію, я перевірив це, і цього більше не відбувається. Напевно, це щось, що було змінено з грудня 2011.
jcollado

18

Джерело вашої плутанини видно у вашому коментарі:

Вся суть операцій під стелею / підлогою полягає в перетворенні плавців на цілі числа!

Суть операцій під стелею та підлогою полягає в округлянні даних з плаваючою комою до цілісних значень . Не робити перетворення типів. Користувачі, яким потрібно отримати цілі значення, можуть зробити явну конверсію після операції.

Зауважте, що неможливо реалізувати раунд до інтегрального значення так само тривіально, якби все, що у вас було, було операцією ceil або float, що повертало ціле число. Вам потрібно спочатку перевірити, чи є вхід у межах представленого цілого діапазону, а потім викликати функцію; вам потрібно буде обробляти NaN та нескінченності окремим кодовим шляхом.

Крім того, ви повинні мати версії стельового та підлогового покриття, які повертають номери з плаваючою комою, якщо ви хочете відповідати IEEE 754 .


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

На жаль, сьогодні я не голосую. Це правильна відповідь, набагато більше, ніж будь-яке обмеження представництва.
Марцін

13
У мої роки програмування я не пригадую, щоб коли-небудь стикався з ситуацією, коли хотів, щоб результат floor / ceil став float замість цілого числа. Той факт, що python3 дійсно повертає цілі числа, показує, що це насправді корисніше робити. Я не купую претензію "точка ..."; видається, що ви визначаєте точку на основі того, що вона робить, а не того, що може захотіти програміст.
ShreevatsaR

2
@ShreevatsaR У мене була така ситуація кілька разів (проте, переважно поза контекстом Python). Часи, які я пам’ятаю - це час роботи з наборами Мандельброта. Іноді потрібно зробити цілісне значення, але потім застосувати деяку операцію з плаваючою точкою до значення відразу після цього (скажімо, масштабування його на 0,5). Тоді набагато ефективніше зберегти floored float і застосувати до нього операцію з плаваючою точкою, ніж спочатку перетворити його на int, а потім негайно перетворити його назад у float.
blubberdiblub

17

Оскільки математична бібліотека пітона є тонкою обгорткою навколо математичної бібліотеки С, яка повертає плаває.


C математична бібліотека підтримує довільні цілі точності? Тому що до цього повертаються інші математичні функції пітона.
ендоліт

5

Перед Python 2.4 ціле число не могло вмістити весь діапазон усічених дійсних чисел.

http://docs.python.org/whatsnew/2.4.html#pep-237-unifying-long-integers-and-integers


2
Зараз він також не може містити "повний спектр усічених реальних чисел", тому що це, очевидно, нескінченний набір і тому потребує нескінченної кількості пам'яті. Він може вмістити діапазон усічених поплавців , що є лише невеликим підмножиною ℝ.
листопада

6
@leftaroundabout - прискіпливий прискіпливий! Ви знали, що я маю на увазі.
Марк Викуп

4

Оскільки діапазон для плавців більший, ніж для цілих чисел - повернення цілого числа може переповнювати


7
Цілі особи не переповнюються в Python; цілі числа перетворюються на bigints, коли вони стають занадто великими. Відкрийте інтерпретатор Python і введіть "2 ** 500", і ви побачите, що ви отримаєте об'єкт, до якого ви можете всіляко ставитися як до int.
koschei

@koschei: Навіть біґінти переповнюються, намагаючись уявити нескінченність.
Стівен Канон

4

Це дуже цікаве питання! Оскільки поплавцю потрібно кілька біт для зберігання експонента (= bits_for_exponent), будь-яке число з плаваючою комою більше, ніж 2**(float_size - bits_for_exponent)завжди, буде цілісним значенням! З іншого боку поплавок з негативним показником дасть один з 1, 0або -1. Це призводить до обговорення цілого діапазону проти плаваючого діапазону, оскільки ці функції просто повертають початкове число всякий раз, коли число виходить за межі цілого числа. Функції python є обгортками Cфункції, і тому це справді недолік Cфункцій, коли вони повинні були повернути ціле число і змусити програміста зробити діапазон / NaN/ Infперевірити перед викликом ceil / floor.

Таким чином, логічна відповідь - це єдиний раз, коли ці функції стануть корисними, вони повернуть значення в межах цілого діапазону, тому факт, що вони повертають поплавок, є помилкою, і ви дуже розумні для цього!


1

Можливо тому, що це роблять і інші мови, тому це загальноприйнята поведінка. (З поважних причин, як показано в інших відповідях)


Або те, що сказав Чарльз. :)
Алмо
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.