Mengapa operasi math.ceil () dan math.floor () Python mengembalikan float alih-alih bilangan bulat?

170

Dapatkah seseorang menjelaskan hal ini (langsung dari dokumen - penekanan pada saya):

math.ceil (x) Mengembalikan langit-langit x sebagai float , nilai integer terkecil lebih besar dari atau sama dengan x.

math.floor (x) Kembalikan lantai x sebagai float , nilai integer terbesar kurang dari atau sama dengan x.

Mengapa .ceildan .floormengembalikan float ketika mereka secara definisi seharusnya menghitung bilangan bulat?


EDIT:

Nah ini punya beberapa argumen yang sangat baik mengapa mereka harus kembali mengapung, dan aku baru saja digunakan untuk ide, ketika @jcollado menunjukkan bahwa mereka sebenarnya melakukan int kembali di Python 3 ...

Yarin
sumber
1
Dugaan saya adalah karena x adalah float, bukan bilangan bulat, tetapi karena saya tidak tahu atau menggunakan Python, saya akan membiarkan orang lain menjawab dengan lebih pasti. :)
Adam V
6
@ Adam- tetapi inti dari operasi langit-langit adalah untuk mengapung ke bilangan bulat!
Yarin
1
Ini juga membuat saya jengkel ketika pertama kali saya menemukannya, karena sepertinya salah. Paling tidak, tidak terlalu sulit untuk digunakan int(floor(n)).
wim
1
Ironisnya (karena float digunakan untuk mencegah overflows), nilai yang dikembalikan oleh floor / ceil tidak ada artinya dalam digit rendah karena representasi float, jauh sebelum int 64 bit akan meluap. [Ini tidak benar di masa lalu 32 bit.]
Yves Daoust

Jawaban:

99

Kisaran angka floating point biasanya melebihi kisaran bilangan bulat. Dengan mengembalikan nilai floating point, fungsi dapat mengembalikan nilai masuk akal untuk nilai input yang berada di luar kisaran integer yang dapat diwakili.

Pertimbangkan: Jika floor()mengembalikan bilangan bulat, apa yang harus floor(1.0e30)dikembalikan?

Sekarang, sementara bilangan bulat Python sekarang presisi yang sewenang-wenang, itu tidak selalu seperti ini. Fungsi pustaka standar adalah pembungkus tipis di sekitar fungsi pustaka C yang setara.

Greg Hewgill
sumber
13
Dan meskipun bilangan bulat Python sekarang presisi sewenang-wenang, masih ada mengapung yang lantai dan langit-langitnya tidak dapat diwakili oleh bilangan bulat. Coba floor(float("inf"))atau ceil(float("nan")).
Michael Hoffman
4
@ Michael- Rupanya di P3 Anda sekarang akan mendapatkan OverflowExceptions jika Anda mencobanya. Lihat jawaban jcollado
Yarin
4
Eh, itu harus mengembalikan tipe 'panjang' (alias 'bigint'), bukan? Sepertinya jawaban yang jelas bagi saya, tetapi sekarang saya merasa seperti saya naif.
koschei
3
@koschei: Itu dilakukan dengan Python 3.x, lihat jawaban jcollado.
Greg Hewgill
Lihat juga komentar untuk jawaban lain mengapa ini masuk akal bahkan untuk nomor yang ada dalam jangkauan.
ivan_pozdeev
96

Seperti yang ditunjukkan oleh jawaban lain, dalam python mereka mengembalikan float mungkin karena alasan historis untuk mencegah masalah meluap. Namun, mereka mengembalikan bilangan bulat dalam python 3.

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

Anda dapat menemukan informasi lebih lanjut di PEP 3141 .

jcollado
sumber
@ jcollado- Di mana Anda melihat bahwa mereka mengembalikan bilangan bulat di P3?
Yarin
4
@ Yarin Saya baru saja mengetik perintah di atas. Juga jika Anda mencoba float("inf")atau float("nan"), Anda akan mendapatkan OverflowErrorpengecualian.
jcollado
10
Untuk kelengkapan, Python numpy.floordan ceilmengapung kembali (<class 'numpy.float64'>)
Neil G
1
@ jcollado: float("inf")tidak menghasilkan pengecualian dalam Python 2.7 atau 3
endolith
1
@ endolith Anda benar, saya telah memeriksanya dan itu tidak terjadi lagi. Mungkin itu adalah sesuatu yang telah diubah sejak Desember 2011.
jcollado
18

Sumber kebingungan Anda jelas dalam komentar Anda:

Inti dari operasi langit-langit adalah untuk mengkonversi float ke integer!

Titik operasi langit-langit dan lantai adalah untuk membulatkan data titik-mengambang ke nilai integral . Tidak melakukan konversi tipe. Pengguna yang perlu mendapatkan nilai integer dapat melakukan konversi eksplisit setelah operasi.

Perhatikan bahwa tidak mungkin untuk menerapkan putaran ke nilai integral sepele jika semua yang Anda miliki adalah operasi langit-langit atau float yang mengembalikan bilangan bulat. Anda harus terlebih dahulu memeriksa apakah input berada dalam kisaran integer yang dapat diwakili, kemudian memanggil fungsinya; Anda perlu menangani NaN dan infinitas dalam jalur kode terpisah.

Selain itu, Anda harus memiliki versi langit-langit dan lantai yang mengembalikan angka floating-point jika Anda ingin menyesuaikan diri IEEE 754 .

Stephen Canon
sumber
Stephen - saya menulis ulang komentar saya - maksud saya bulat, bukan bertobat. Tapi itu bukan sumber kebingungan saya - melainkan karena saya tidak mengenali perbedaan jangkauan.
Yarin
Sayangnya, saya tidak bisa memilih hari ini. Ini adalah jawaban yang benar, lebih dari batasan representasi.
Marcin
13
Dalam tahun-tahun pemrograman saya, saya tidak ingat pernah menghadapi situasi di mana saya ingin hasil lantai / langit-langit menjadi pelampung bukan bilangan bulat. Fakta bahwa python3 tidak bilangan bulat kembali menunjukkan bahwa ini sebenarnya hal yang lebih berguna untuk dilakukan. Saya tidak membeli klaim "the point of ..."; tampaknya Anda mendefinisikan titik berdasarkan pada apa yang dilakukannya, bukan apa yang mungkin diinginkan seorang programmer.
ShreevatsaR
2
@ ShreevatsaR Saya mengalami situasi itu beberapa kali (namun, terutama di luar konteks Python). Waktu yang saya ingat adalah ketika bekerja dengan set Mandelbrot. Kadang-kadang Anda perlu membuat nilai integral, tetapi kemudian menerapkan beberapa operasi floating point ke nilai segera sesudahnya (katakanlah, menskalakannya dengan 0,5). Maka itu jauh lebih efisien untuk menjaga lantai mengapung dan menerapkan operasi titik mengambang untuk itu daripada pertama-tama mengubahnya menjadi int dan kemudian segera mengubahnya kembali menjadi mengambang.
blubberdiblub
17

Karena perpustakaan matematika python adalah pembungkus tipis di sekitar perpustakaan matematika C yang mengembalikan mengapung.

Charles
sumber
Perpustakaan C matematika mendukung bilangan bulat presisi sewenang-wenang? Karena itulah yang mengembalikan fungsi python matematika lainnya.
endolith
5

Sebelum Python 2.4, bilangan bulat tidak dapat menampung seluruh bilangan real terpotong.

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

Mark tebusan
sumber
2
Ia tidak dapat menyimpan "kisaran bilangan real terpotong" sekarang, juga, karena itu jelas merupakan himpunan yang tak terbatas dan karenanya akan memerlukan jumlah memori yang tak terbatas. Itu bisa menampung kisaran mengapung terpotong , yang hanyalah sebagian kecil dari ℝ.
leftaroundabout
6
@leftaroundabout - pilih-pilih pilih-pilih! Anda tahu apa yang saya maksud.
Mark Ransom
4

Karena rentang untuk mengapung lebih besar daripada bilangan bulat - mengembalikan bilangan bulat bisa meluap

kyle
sumber
7
Integer tidak meluap dengan Python; integernya dikonversi menjadi bigints ketika mereka menjadi terlalu besar. Buka interpreter Python dan ketik "2 ** 500", dan Anda akan melihat bahwa Anda mendapatkan objek yang bisa Anda perlakukan dengan segala cara seperti int.
koschei
@koschei: Bahkan bigints meluap ketika mencoba merepresentasikan infinity.
Stephen Canon
4

Ini pertanyaan yang sangat menarik! Karena float membutuhkan beberapa bit untuk menyimpan eksponen (= bits_for_exponent) angka floating point yang lebih besar daripada 2**(float_size - bits_for_exponent)selalu akan menjadi nilai integral! Pada ekstrem yang lain pelampung dengan eksponen negatif akan memberikan salah satu 1, 0atau -1. Hal ini membuat pembahasan rentang integer versus float range dapat diperdebatkan karena fungsi-fungsi ini hanya akan mengembalikan nomor asli setiap kali nomor tersebut berada di luar kisaran tipe integer. Fungsi python adalah pembungkus Cfungsi dan jadi ini benar-benar kekurangan Cfungsi di mana mereka seharusnya mengembalikan integer dan memaksa programmer untuk melakukan range / NaN/Inf check sebelum memanggil ceil / floor.

Dengan demikian jawaban logis adalah satu-satunya waktu fungsi ini berguna mereka akan mengembalikan nilai dalam rentang integer dan fakta bahwa mereka mengembalikan float adalah kesalahan dan Anda sangat pintar untuk mewujudkan ini!

Justin Finnerty
sumber
1

Mungkin karena bahasa lain melakukan ini juga, jadi itu adalah perilaku yang diterima secara umum. (Untuk alasan yang baik, seperti yang ditunjukkan pada jawaban lain)

Almo
sumber
Atau apa yang dikatakan Charles. :)
Almo