Dlaczego operacje math.ceil () i math.floor () w Pythonie zwracają liczby zmiennoprzecinkowe zamiast liczb całkowitych?

170

Czy ktoś może to wyjaśnić (prosto z dokumentacji - moje podkreślenie):

math.ceil (x) Zwraca pułap x jako liczbę zmiennoprzecinkową , czyli najmniejszą liczbę całkowitą większą lub równą x.

math.floor (x) Zwraca podłogę x jako liczbę zmiennoprzecinkową , czyli największą liczbę całkowitą mniejszą lub równą x.

Dlaczego .ceili .floorzwracać liczby zmiennoprzecinkowe, skoro z definicji mają obliczać liczby całkowite?


EDYTOWAĆ:

Cóż to ma kilka bardzo dobrych argumentów, dlaczego oni powinni powrócić pływaków, a ja po prostu przyzwyczaić do myśli, kiedy @jcollado podkreślić, że w rzeczywistości zrobić ints powróci w Pythonie 3 ...

Yarin
źródło
1
Domyślam się, że dzieje się tak dlatego, że x jest liczbą zmiennoprzecinkową, a nie liczbą całkowitą, ale ponieważ nie znam ani nie używam Pythona, pozwolę komuś innemu odpowiedzieć bardziej definitywnie. :)
Adam V
6
@ Adam- ale celem operacji na suficie / podłodze jest zaokrąglanie liczb zmiennoprzecinkowych do liczb całkowitych!
Yarin,
1
To też mnie zirytowało, gdy pierwszy raz go spotkałem, ponieważ po prostu wydaje się niewłaściwy. Przynajmniej nie jest zbyt trudny w użyciu int(floor(n)).
wim
1
Jak na ironię (ponieważ zmiennoprzecinkowe były używane do zapobiegania przepełnieniom), wartość zwracana przez wartość podłoga / sufit jest bez znaczenia w małych cyfrach ze względu na reprezentację zmiennoprzecinkową, na długo przed przepełnieniem 64-bitowej wartości int. [To nie było prawdą w dawnych czasach 32 bitów.]
Yves Daoust

Odpowiedzi:

99

Zakres liczb zmiennoprzecinkowych zwykle przekracza zakres liczb całkowitych. Zwracając wartość zmiennoprzecinkową, funkcje mogą zwracać sensowną wartość dla wartości wejściowych, które znajdują się poza możliwym do przedstawienia zakresem liczb całkowitych.

Zastanów się: jeśli floor()zwracana jest liczba całkowita, co powinno floor(1.0e30)zwrócić?

Chociaż liczby całkowite w Pythonie mają teraz dowolną precyzję, nie zawsze tak było. Standardowe funkcje biblioteczne są cienkimi opakowaniami wokół równoważnych funkcji biblioteki C.

Greg Hewgill
źródło
13
I chociaż liczby całkowite w Pythonie mają teraz dowolną precyzję, wciąż istnieją zmienne, których podłoga i sufit nie mogą być reprezentowane przez liczby całkowite. Spróbuj floor(float("inf"))lub ceil(float("nan")).
Michael Hoffman,
4
@ Michael - Najwyraźniej w P3 otrzymasz teraz OverflowExceptions, jeśli spróbujesz tego. Zobacz jcollado „s odpowiedź
Yarin
4
Eee, powinien zwrócić „długi” typ (znany również jako „bigint”), prawda? Wydaje mi się oczywistą odpowiedzią, ale teraz czuję, że jestem naiwny.
koschei
3
@koschei: Działa w Pythonie 3.x, zobacz odpowiedź jcollado.
Greg Hewgill,
Zobacz także komentarz do innej odpowiedzi, dlaczego ma to sens nawet w przypadku liczb znajdujących się w zakresie.
ivan_pozdeev
96

Jak wskazano w innych odpowiedziach, w Pythonie zwracają zmienne prawdopodobnie z powodów historycznych, aby zapobiec problemom z przepełnieniem. Jednak zwracają liczby całkowite w Pythonie 3.

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

Więcej informacji można znaleźć w PEP 3141 .

jcollado
źródło
@ jcollado- Gdzie widzisz, że zwracają liczby całkowite w P3?
Yarin,
4
@Yarin Właśnie wpisałem powyższe polecenia. Również jeśli spróbujesz z float("inf")lub float("nan"), otrzymasz OverflowErrorwyjątek.
jcollado,
10
Aby uzyskać kompletność, Python's numpy.floori ceilreturn float (<class 'numpy.float64'>)
Neil G
1
@jcollado: float("inf")nie tworzy wyjątku w Pythonie 2.7 lub 3
endolith
1
@endolith Masz rację, sprawdziłem to i już się nie dzieje. Prawdopodobnie zmieniło się to od grudnia 2011 roku.
jcollado
18

Źródło twojego zamieszania jest ewidentne w twoim komentarzu:

Głównym celem operacji ceil / floor jest konwersja liczb zmiennoprzecinkowych na liczby całkowite!

Celem operacji na suficie i podłodze jest zaokrąglenie danych zmiennoprzecinkowych do wartości całkowitych . Nie robić konwersji typu. Użytkownicy, którzy muszą uzyskać wartości całkowite , mogą wykonać jawną konwersję po operacji.

Zauważ, że nie byłoby możliwe zaimplementowanie zaokrąglenia do wartości całkowitej w tak trywialny sposób, gdyby wszystko, co było dostępne, to operacja ceil lub float, która zwracała liczbę całkowitą. Najpierw musisz sprawdzić, czy dane wejściowe mieszczą się w reprezentowalnym zakresie liczb całkowitych, a następnie wywołaj funkcję; musiałbyś obsługiwać NaN i nieskończoności w oddzielnej ścieżce kodu.

Ponadto musisz mieć wersje ceil i floor, które zwracają liczby zmiennoprzecinkowe, jeśli chcesz zachować zgodność z IEEE 754 .

Stephen Canon
źródło
Stephen - przepisałem swój komentarz - miałem na myśli okrągły, a nie konwersję. Ale to nie było źródło mojego zamieszania - raczej to, że nie dostrzegałem dysproporcji w zakresie.
Yarin
Niestety nie mam dzisiaj głosów. To jest prawidłowa odpowiedź, dużo bardziej niż jakiekolwiek ograniczenie reprezentacji.
Marcin
13
Podczas moich lat programowania nie przypominam sobie, by kiedykolwiek spotkałem się z sytuacją, w której chciałbym, aby wynik podłoga / sufit był zmienną, a nie liczbą całkowitą. Fakt, że python3 robi liczby całkowite powrotne pokazuje, że jest w rzeczywistości bardziej przydatna rzecz. Nie kupuję twierdzenia „punkt ...”; wygląda na to, że definiujesz punkt na podstawie tego, co robi, a nie tego, czego może chcieć programista.
ShreevatsaR
2
@ShreevatsaR Miałem taką sytuację kilka razy (jednak głównie poza kontekstem Pythona). Pamiętam czasy, kiedy pracowałem z zestawami Mandelbrota. Czasami trzeba podać wartość całkowitą, ale zaraz potem zastosować pewną operację zmiennoprzecinkową (powiedzmy, skalując ją o 0,5). Wtedy znacznie bardziej wydajne jest zachowanie zmiennoprzecinkowej liczby zmiennoprzecinkowej i zastosowanie do niej operacji zmiennoprzecinkowej niż najpierw przekonwertowanie jej na wartość typu int, a następnie natychmiastowe przekonwertowanie z powrotem na zmiennoprzecinkową.
blubberdiblub
17

Ponieważ biblioteka matematyczna Pythona jest cienkim opakowaniem wokół biblioteki matematycznej C, która zwraca liczby zmiennoprzecinkowe.

Charles
źródło
Biblioteka matematyczna C obsługuje liczby całkowite o dowolnej dokładności? Ponieważ to właśnie zwracają inne funkcje matematyczne języka Python.
endolith
5

Przed Pythonem 2.4 liczba całkowita nie mogła zawierać pełnego zakresu obciętych liczb rzeczywistych.

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

Mark Okup
źródło
2
Nie może też teraz pomieścić „pełnego zakresu obciętych liczb rzeczywistych”, ponieważ jest to oczywiście nieskończony zbiór i dlatego wymagałby nieskończonej ilości pamięci. Może zawierać zakres obciętych liczb zmiennoprzecinkowych , który jest tylko niewielkim podzbiorem ℝ.
leftaroundokoło
6
@leftaroundabout - wybredny! Wiedziałeś, co mam na myśli.
Mark Ransom
4

Ponieważ zakres liczb zmiennoprzecinkowych jest większy niż zakres liczb całkowitych, zwrócenie liczby całkowitej może spowodować przepełnienie

kyle
źródło
7
Liczby całkowite nie przepełniają się w Pythonie; jego liczby całkowite zamieniają się na biginty, gdy stają się zbyt duże. Otwórz interpreter Pythona i wpisz „2 ** 500”, a zobaczysz, że otrzymasz obiekt, który możesz traktować pod każdym względem jak int.
koschei
@koschei: Nawet biginti przepełniają się, gdy próbujesz przedstawić nieskończoność.
Stephen Canon
4

To bardzo interesujące pytanie! Ponieważ liczba zmiennoprzecinkowa wymaga pewnych bitów do przechowywania wykładnika (= bits_for_exponent), każda liczba zmiennoprzecinkowa większa niż 2**(float_size - bits_for_exponent)zawsze będzie wartością całkowitą! Na drugim biegunie pływak o wykładniku ujemnym dadzą jedną 1, 0lub -1. To sprawia, że dyskusję o zakresie całkowitej kontra zakres pływak Moot ponieważ funkcje te będą po prostu wrócić oryginalny numer, gdy numer jest poza zakres typu całkowitego. Funkcje Pythona są opakowaniami Cfunkcji, więc jest to w rzeczywistości brak Cfunkcji, w których powinny one zwrócić liczbę całkowitą i zmusić programistę do sprawdzenia zakresu / NaN/ Infprzed wywołaniem ceil / floor.

Zatem logiczną odpowiedzią jest jedyny przypadek, w którym te funkcje są użyteczne i zwracają wartość z zakresu liczb całkowitych, więc fakt, że zwracają wartość zmiennoprzecinkową, jest błędem i jesteś bardzo sprytny, aby to zrozumieć!

Justin Finnerty
źródło
1

Może dlatego, że robią to również inne języki, więc jest to ogólnie akceptowane zachowanie. (Z ważnych powodów, jak pokazano w innych odpowiedziach)

Almo
źródło
Albo co powiedział Charles. :)
Almo,