Por que as operações math.ceil () e math.floor () do Python retornam floats em vez de números inteiros?

170

Alguém pode explicar isso (direto dos documentos - ênfase minha):

math.ceil (x) Retorna o teto de x como um ponto flutuante , o menor valor inteiro maior ou igual a x.

math.floor (x) Retorna o piso de x como um ponto flutuante , o maior valor inteiro menor ou igual a x.

Por que .ceile .floorreturn flutuam quando, por definição, deveriam calcular números inteiros?


EDITAR:

Bem, isso tem alguns muito bons argumentos a respeito de por que eles devem retornar carros alegóricos, e eu estava apenas se acostumando com a idéia, quando @jcollado apontou que eles de fato fazer ints retorno em Python 3 ...

Yarin
fonte
1
Meu palpite seria que é porque x é um float, não um número inteiro, mas como não conheço ou uso o Python, deixarei que outra pessoa responda mais definitivamente. :)
Adam V
6
@ Adam- mas o objetivo das operações de teto / piso é arredondar carros alegóricos para números inteiros!
Yarin
1
Isso também me irritou na primeira vez que me deparei com isso, porque parece errado. Pelo menos, não é muito difícil de usar int(floor(n)).
Wim
1
Ironicamente (como flutuadores foram usados ​​para evitar estouros), o valor retornado pelo piso / teto não faz sentido nos dígitos baixos devido à representação do flutuador, muito antes de um int de 64 bits estourar. [Isto não era verdade nos velhos dias de 32 bits.]
Yves Daoust

Respostas:

99

O intervalo de números de ponto flutuante geralmente excede o intervalo de números inteiros. Ao retornar um valor de ponto flutuante, as funções podem retornar um valor sensível para valores de entrada que estão fora do intervalo representável de números inteiros.

Considere: Se floor()retornou um número inteiro, o que deve floor(1.0e30)retornar?

Agora, enquanto os números inteiros do Python agora são precisão arbitrária, nem sempre foi assim. As funções padrão da biblioteca são invólucros finos em torno das funções equivalentes da biblioteca C.

Greg Hewgill
fonte
13
E embora os números inteiros do Python agora sejam precisão arbitrária, ainda existem flutuadores cujo piso e teto não podem ser representados por números inteiros. Tente floor(float("inf"))ou ceil(float("nan")).
Michael Hoffman
4
@ Michael- Aparentemente, na P3 agora você terá OverflowExceptions se tentar isso. Veja a resposta de jcollado
Yarin
4
Er, ele deve retornar um tipo 'longo' (também conhecido como 'bigint'), não deveria? Parece uma resposta óbvia para mim, mas agora sinto que estou sendo ingênuo de alguma forma.
Koschei
3
@koschei: Sim, no Python 3.x, veja a resposta do jcollado.
Greg Hewgill
Veja também um comentário para outra resposta por que isso faz sentido, mesmo para números que estão dentro do alcance.
ivan_pozdeev
96

Como apontado por outras respostas, em python eles retornam flutuadores provavelmente por razões históricas para evitar problemas de estouro. No entanto, eles retornam números inteiros no python 3.

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

Você pode encontrar mais informações no PEP 3141 .

jcollado
fonte
@ jcollado- Onde você vê que eles retornam números inteiros em P3?
Yarin
4
@ Yarin Acabei de digitar os comandos acima. Além disso, se você tentar com float("inf")ou float("nan"), receberá uma OverflowErrorexceção.
jcollado
10
Para completar, os flutuadores Python numpy.floore de ceilretorno (<class 'numpy.float64'>)
Neil G
1
@jcollado: float("inf")não produz uma exceção no Python 2.7 ou 3
endolith
1
@ Endolith Você está certo, eu verifiquei isso e isso não acontece mais. Provavelmente isso mudou desde dezembro de 2011.
jcollado
18

A fonte de sua confusão é evidente em seu comentário:

O objetivo das operações de teto / piso é converter carros alegóricos em números inteiros!

O ponto das operações de teto e piso é arredondar os dados de ponto flutuante para valores integrais . Não para fazer uma conversão de tipo. Usuários que precisam obter números inteiros valores podem fazer uma conversão explícita após a operação.

Observe que não seria possível implementar uma rodada para o valor integral como trivial se tudo que você tivesse disponível fosse uma operação de teto ou flutuação que retornasse um número inteiro. Você precisaria primeiro verificar se a entrada está dentro do intervalo inteiro representável e depois chamar a função; você precisaria lidar com NaN e infinitos em um caminho de código separado.

Além disso, você deve ter versões de teto e piso que retornam números de ponto flutuante se desejar estar em conformidade com a IEEE 754 .

Stephen Canon
fonte
Stephen - eu reescrevi meu comentário - eu quis dizer rodada, não converter. Mas essa não foi a fonte da minha confusão - pelo contrário, eu não estava reconhecendo a disparidade de alcance.
Yarin
Infelizmente, hoje estou sem votos. Esta é a resposta correta, muito mais do que qualquer limitação de representação.
7683 Marcin
13
Nos meus anos de programação, não me lembro de ter encontrado uma situação em que queria que o resultado do piso / teto fosse um flutuador em vez de um número inteiro. O fato de que python3 faz inteiros de retorno mostra que este é de fato a coisa mais útil para fazer. Não compro a afirmação "o ponto de ..."; parece que você está definindo o ponto com base no que ele faz, e não no que um programador pode querer.
ShreevatsaR
2
@ShreevatsaR Eu tive essa situação algumas vezes (no entanto, principalmente fora de um contexto Python). As vezes que me lembro são quando trabalho com conjuntos de Mandelbrot. Às vezes, você precisa criar um valor integral, mas aplicar alguma operação de ponto flutuante ao valor imediatamente depois (por exemplo, escalando-o em 0,5). Então é muito mais eficiente manter a flutuação no piso e aplicar uma operação de ponto flutuante a ela do que primeiro convertê-la em int e depois convertê-la imediatamente novamente em flutuação.
precisa saber é o seguinte
17

Como a biblioteca de matemática do python é um invólucro fino em torno da biblioteca de matemática C que retorna valores flutuantes.

Charles
fonte
A biblioteca matemática C suporta números inteiros de precisão arbitrários? Porque é isso que outras funções matemáticas python retornam.
Endolith 14/10
5

Antes do Python 2.4, um número inteiro não podia conter toda a gama de números reais truncados.

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

Mark Ransom
fonte
2
Agora, também não pode conter o "intervalo completo de números reais truncados", porque esse é obviamente um conjunto infinito e, portanto, exigiria uma quantidade infinita de memória. Ele pode conter o intervalo de flutuadores truncados , que é apenas um pequeno subconjunto de ℝ.
usar o seguinte comando
6
@leftaroundabout - exigente exigente! Você sabia o que eu quis dizer.
Mark Ransom
4

Como o intervalo para flutuadores é maior que o de números inteiros - retornar um número inteiro pode estourar

kyle
fonte
7
Inteiros não transbordam em Python; seus números inteiros se convertem em bigints quando se tornam muito grandes. Abra um intérprete Python e digite "2 ** 500" e você verá um objeto que pode ser tratado de todas as maneiras como um int.
Koschei
@koschei: Até os bigints transbordam ao tentar representar o infinito.
Stephen Canon
4

Esta é uma questão muito interessante! Como um flutuador requer alguns bits para armazenar o expoente (= bits_for_exponent) qualquer número de ponto flutuante maior que 2**(float_size - bits_for_exponent)sempre será um valor integral! No outro extremo, um flutuador com um expoente negativo dará um de 1, 0ou -1. Isso torna discutível o intervalo inteiro versus o intervalo flutuante flutuante, porque essas funções retornam simplesmente o número original sempre que o número estiver fora do intervalo do tipo inteiro. As funções python são invólucros da Cfunção e, portanto, é realmente uma deficiência das Cfunções nas quais elas deveriam ter retornado um número inteiro e forçado o programador a fazer o intervalo / NaN/ Infcheck antes de chamar Ceil / Floor.

Portanto, a resposta lógica é a única vez em que essas funções são úteis, elas retornariam um valor dentro do intervalo inteiro e, portanto, o fato de retornarem uma flutuação é um erro e você é muito inteligente para perceber isso!

Justin Finnerty
fonte
1

Talvez porque outras línguas façam isso também, seja um comportamento geralmente aceito. (Por boas razões, como mostrado nas outras respostas)

Almo
fonte
Ou o que Charles disse. :)
Almo