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

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

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

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

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


EDIT:

Хорошо, у этого были очень хорошие аргументы в пользу того, почему они должны возвращать float, и я просто привык к идее, когда @jcollado указал, что они в факт действительно возвращает ints в Python 3...

Ответ 1

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

Рассмотрим: если floor() возвращено целое число, что должно floor(1.0e30) вернуть?

Теперь, когда целые числа Python теперь являются произвольной точностью, это не всегда так. Стандартные функции библиотеки - это тонкие обертки вокруг эквивалентных функций библиотеки C.

Ответ 2

Как указывалось другими ответами, в python они возвращают float, вероятно, из-за исторических причин, чтобы предотвратить проблемы с переполнением. Тем не менее, они возвращают целые числа в python 3.

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

Дополнительную информацию можно найти в PEP 3141.

Ответ 3

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

Ответ 4

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

Весь смысл операций по потолку/полу состоит в том, чтобы конвертировать поплавки в целые числа!

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

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

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

Ответ 6

Поскольку диапазон для float больше, чем диапазон целых чисел - возвращение целого числа может переполняться

Ответ 7

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

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

Ответ 8

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

Ответ 9

В противном случае вы не могли этого сделать.

math.floor(23.45678 * 1000) / 1000

Если math.floor вернет целое число в Python 2, это вернет 23, а не 23.456, что вы имели в виду. В Python 3 это безопасно, так как / всегда является делением с плавающей запятой.