Apa alasan perbedaan antara pembagian integer dan float ke konversi int dengan python?

52

Saya baru-baru ini memperhatikan bahwa int()putaran float ke arah 0, sedangkan divisi integer putaran float ke lantai.

contohnya:

-7 // 2 = -4
int(-7/2) = -3

Saya telah membaca dokumentasi yang menjelaskan:

kelas int (x, basis = 10)

Kembalikan objek integer yang dibangun dari angka atau string x, atau kembalikan 0 jika tidak ada argumen yang diberikan>. Jika x adalah angka, kembalikan x. int (). Untuk angka floating point, ini memotong menuju nol.

dan:

divisi lantai

Divisi matematika yang membulatkan ke bilangan bulat terdekat. Operator divisi lantai adalah //. Misalnya, ekspresi 11 // 4 mengevaluasi ke 2 berbeda dengan 2,75 yang dikembalikan oleh float true division. Perhatikan bahwa (-11) // 4 adalah -3 karena itu adalah -2.75 dibulatkan ke bawah. Lihat PEP 238.

Tetapi tampaknya tidak masuk akal bagi saya bahwa 2 operasi serupa (float division to integer) harus mengembalikan hasil yang berbeda.

Apakah ada motivasi untuk perbedaan antara fungsi?

Terima kasih.

IsaacDj
sumber
Tautan yang relevan: python-history.blogspot.com/2010/08/...
dan04

Jawaban:

61

Konsistensi.

Anda harus mengikuti beberapa penjelasan yang sangat mendasar dan tampaknya tidak relevan untuk memahaminya.

Di sekolah Anda telah belajar pembagian dengan sisanya. Dan Anda telah melakukan perhitungan seperti ini:

8 ÷ 4 = 2 R 0
7 ÷ 4 = 1 R 3
6 ÷ 4 = 1 R 2
5 ÷ 4 = 1 R 1
4 ÷ 4 = 1 R 0
3 ÷ 4 = 0 R 3
2 ÷ 4 = 0 R 2
1 ÷ 4 = 0 R 1
0 ÷ 4 = 0 R 0
        ^------ This is the result of x // 4
            ^-- This is the result of x % 4 (modulo)

Kemudian, Anda telah mempelajari pembagian untuk bilangan real:

8 ÷ 4 = 2.0
7 ÷ 4 = 1.75
6 ÷ 4 = 1.5
5 ÷ 4 = 1.25
4 ÷ 4 = 1.0
3 ÷ 4 = 0.75
2 ÷ 4 = 0.5
1 ÷ 4 = 0.25
0 ÷ 4 = 0.0
        ^--- Note that the number in front of the . is int(x/4)

Sampai titik ini, Anda mungkin percaya itu x // 4dan int(x/4)selalu memberikan hasil yang sama. Itulah pemahaman Anda tentang situasi saat ini.

Namun, lihat apa yang terjadi di divisi bilangan bulat: angka di belakang R siklus dari 3, 2, 1 ke 0 dan kemudian restart: 3, 2, 1, 0. Angka di depan R menurun setiap langkah ke-4.

Jadi, bagaimana kelanjutannya?

 8 ÷ 4 =  2 R 0
 7 ÷ 4 =  1 R 3
 6 ÷ 4 =  1 R 2
 5 ÷ 4 =  1 R 1
 4 ÷ 4 =  1 R 0
 3 ÷ 4 =  0 R 3
 2 ÷ 4 =  0 R 2
 1 ÷ 4 =  0 R 1
 0 ÷ 4 =  0 R 0
-1 ÷ 4 = -1 R 3
         ^------ We have to decrease now, because we already have 0 four times
              ^-- We have to restart the cycle at 3

Pada saat yang sama, pembagian bilangan real memberi kita:

-1 ÷ 4 = -0.25
          ^----- There is still a 0 in front of the .

Itu sebabnya -1 // 4memberi -1 tetapi int(-1/4)memberi 0.

Apakah ada motivasi untuk perbedaan antara fungsi?

Yah, mereka melayani tujuan yang berbeda: //adalah bagian dari perhitungan bilangan bulat dengan sisa dan int()memberi Anda bagian di depan .operasi bilangan real.

Anda memutuskan apa yang ingin Anda hitung, maka Anda memutuskan operator mana yang akan digunakan dalam Python untuk mendapatkan hasil yang benar.

Pertanyaan bagus. Teruslah belajar.

Thomas Weller
sumber
11
Dalam praktiknya, ini memungkinkan untuk trik: Jika Anda memiliki -1 permen dan Anda membagikannya kepada 4 teman, maka akan ada 3 permen tersisa. Bagus bukan? Anda hanya perlu mengetahui cara memiliki -1 permen.
Thomas Weller
1
Itu memang menciptakan semacam konsistensi namun sejauh yang saya mengerti motivasi dalam menambahkan //operator di python 3 adalah untuk menghindari memaksa penggunaan int (float). Jika ini tidak terjadi, kapan saya harus memilih untuk menerapkan menggunakan int()dan kapan saya harus menerapkan menggunakan//
IsaacDj
1
Ok, kalau begitu itu anggapan yang salah. Itu tidak ada yang buruk, selama Anda menguji asumsi Anda untuk kebenaran, yang mungkin gagal dalam 50% kasus (setidaknya itu berlaku untuk saya). Saya menambahkan beberapa kata tentang itu dalam jawabannya.
Thomas Weller
2
@IsaacDj Anda mungkin ingin membaca ini untuk kisah di balik operator "divisi lantai".
bruno desthuilliers
1
@ EricLippert: Saya tidak berpikir itu aneh. Kami tidak dapat mengasumsikan bahwa operasi lossy memberikan hasil yang sama dengan operasi yang tepat. Diucapkan dalam kode: Math.Floor(3.23) != -Math.Floor(-3.23)Untuk alasan yang sama -((-x)//y)tidak perlu sama x//y.
Thomas Weller
4

Saya akan mengatakan bahwa pengamatan Anda bahwa kedua operasi tersebut harus serupa secara intuitif diharapkan karena pada angka positif mereka berperilaku identik. Tetapi jika Anda melihat asal-usul mereka (satu berasal dari matematika dan yang lainnya dari ilmu komputer) maka lebih masuk akal perilaku mereka yang berbeda.

Anda dapat melihat konsep di belakang sana:

  • Divisi lantai alias fungsi lantai diterapkan ke divisi matematika
  • Jenis konversi / casting jenis

================================================== ================

I) Divisi lantai alias fungsi lantai diterapkan ke divisi matematika

Fungsi lantai adalah konsep yang sangat mapan dalam matematika.

Dari mathworld.wolfram :

Fungsi lantai | _ x_ |, juga disebut fungsi integer terbesar atau nilai integer (Spanier dan Oldham 1987), memberikan integer terbesar kurang dari atau sama dengan x. Nama dan simbol untuk fungsi lantai diciptakan oleh KE Iverson (Graham et al. 1994)

Jadi pembagian lantai tidak lebih dari fungsi lantai yang diterapkan pada pembagian matematika. Perilaku ini sangat jelas, "tepat secara matematis".

II) Jenis konversi / Jenis casting

Dari wikipedia :

Dalam ilmu komputer, konversi tipe, tipe casting, tipe paksaan, dan jenis juggling adalah cara berbeda untuk mengubah ekspresi dari satu tipe data ke yang lainnya.

Di sebagian besar bahasa pemrograman, bentuk casting float to integer diterapkan oleh aturan pembulatan (jadi ada konvensi):

  • Putaran menuju 0 - pembulatan terarah menuju nol (juga dikenal sebagai pemotongan)

Aturan pembulatan menurut IEEE 754 .


Jadi, dengan kata lain, alasan untuk perbedaan antara pembagian bilangan bulat dan float ke konversi int dengan python adalah matematika, berikut adalah beberapa pemikiran dari Guido van Rossum (saya kira saya tidak harus memperkenalkannya: D) (dari blog Sejarah Python, artikel "Mengapa Lantai Divisi Integer Python" )

Ini mengganggu sebagian orang, tetapi ada alasan matematika yang bagus. Operasi pembagian integer (//) dan saudara kandungnya, operasi modulo (%), berjalan bersama dan memuaskan hubungan matematis yang bagus (semua variabel adalah integer):

a / b = q dengan sisa r

seperti yang

b * q + r = a dan 0 <= r <b

(dengan asumsi a dan b adalah> = 0).

kederrac
sumber