Почему операции Python math.ceil () и math.floor () возвращают числа с плавающей точкой вместо целых чисел?

170

Может кто-нибудь объяснить это (прямо из документов - выделение мое):

math.ceil (x) Возвращает потолок x в виде числа с плавающей точкой , наименьшее целочисленное значение, большее или равное x.

math.floor (x) Возвращает пол x как число с плавающей запятой , наибольшее целочисленное значение меньше или равно x.

Зачем .ceilи .floorвозвращать числа с плавающей точкой, если они по определению должны вычислять целые числа?


РЕДАКТИРОВАТЬ:

Ну это имеет очень хорошие аргументы, почему они должны возвращаться поплавки, и я просто привыкнуть к идее, когда @jcollado отметил, что они на самом деле делают возвращение РАСЧ в Python 3 ...

Ярина
источник
1
Я думаю, это потому, что x - это число с плавающей точкой, а не целое число, но, поскольку я не знаю и не использую Python, я позволю кому-то другому ответить более определенно. :)
Адам V
6
@ Адам, но вся суть операций ceil / floor заключается в округлении числа с плавающей точкой до целых чисел!
Ярин
1
Это также раздражало меня в первый раз, когда я столкнулся с этим, потому что это только кажется неправильным. По крайней мере, это не так уж сложно использовать int(floor(n)).
Вим
1
По иронии судьбы (поскольку float использовались для предотвращения переполнения), значение, возвращаемое floor / ceil, не имеет смысла в младших разрядах из-за представления с плавающей точкой задолго до того, как 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), не так ли? Мне кажется, что это очевидный ответ, но теперь я чувствую, что я как-то наивен.
Кощей
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
источник
@ jcollado- Где вы видите, что они возвращают целые числа в P3?
Ярин
4
@ Ярин Я только что набрал команды выше. Также, если вы попробуете с float("inf")или float("nan"), вы получите OverflowErrorисключение.
Jcollado
10
Для полноты, Python numpy.floorи ceilобратные числа с плавающей точкой (<class 'numpy.float64'>)
Нил Г
1
@jcollado: float("inf")не создает исключение в Python 2.7 или 3
endolith
1
@endolith Вы правы, я проверил это, и это больше не происходит. Вероятно, это то, что изменилось с декабря 2011 года.
Jcollado
18

Источник вашего замешательства очевиден в вашем комментарии:

Весь смысл операций ceil / floor - преобразовать числа с плавающей точкой в ​​целые числа!

Целью операций ceil и floor является округление данных с плавающей запятой до целых значений . Не делать преобразование типов. Пользователи, которым необходимо получить целочисленные значения, могут выполнить явное преобразование после операции.

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

Кроме того, у вас должны быть версии ceil и floor, которые возвращают числа с плавающей запятой, если вы хотите соответствовать IEEE 754 .

Стивен Кэнон
источник
Стивен, - я переписал свой комментарий, - я имел в виду, а не конвертировать. Но это не было источником моего замешательства, скорее это было то, что я не признавал несоответствие диапазона.
Ярин
К сожалению, у меня сегодня нет голосов. Это правильный ответ, гораздо больше, чем любое ограничение представления.
Марцин
13
За те годы, что я программировал, я не помню, чтобы когда-либо сталкивался с ситуацией, когда я хотел, чтобы результатом floor / ceil был float вместо целого числа. Тот факт , что python3 делает возвращение целых чисел показывает , что это на самом деле более полезным делом. Я не покупаю претензию "точка ..."; кажется, что вы определяете точку зрения, основываясь на том, что она делает, а не на том, что может захотеть программист.
ShreevatsaR
2
@ShreevatsaR У меня была такая ситуация пару раз (однако, в основном вне контекста Python). Времена, которые я помню, были при работе с наборами Мандельброта. Иногда вам нужно сделать целочисленное значение, но затем сразу применить к значению некоторую операцию с плавающей запятой (скажем, масштабируя ее на 0,5). Тогда гораздо эффективнее сохранить float и применить к нему операцию с плавающей запятой, чем сначала преобразовать его в int, а затем немедленно преобразовать обратно в float.
blubberdiblub
17

Потому что математическая библиотека python является тонкой оболочкой для математической библиотеки C, которая возвращает значения с плавающей точкой.

Чарльз
источник
Математическая библиотека C поддерживает произвольные целые числа точности? Потому что это то, что возвращают другие математические функции Python.
эндолит
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; его целые числа преобразуются в большие, когда они становятся слишком большими. Откройте интерпретатор Python и введите «2 ** 500», и вы увидите, что вы получаете объект, который вы можете обрабатывать любым способом, как int.
Кощей
@koschei: даже bigints переполняются при попытке представить бесконечность.
Стивен Кэнон
4

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

Таким образом, логический ответ - единственный раз, когда эти функции полезны, они возвращают значение в целочисленном диапазоне, и поэтому тот факт, что они возвращают число с плавающей запятой, является ошибкой, и вы очень разумны для реализации этого!

Джастин Финнерти
источник
1

Может быть, потому что это делают и другие языки, поэтому это общепринятое поведение. (По уважительным причинам, как показано в других ответах)

Almo
источник
Или то, что сказал Чарльз. :)
Almo