Apa perilaku pembagian bilangan bulat?


211

Sebagai contoh,

int result;

result = 125/100;

atau

result = 43/100;

Apakah hasilnya akan selalu menjadi dasar divisi? Apa perilaku yang didefinisikan?


5
Ringkasan: divisi integer yang ditandatangani terpotong ke arah nol . Untuk hasil non-negatif, ini sama dengan lantai (bulat menuju -Infinity). (Hati-hati karena C89 tidak menjamin ini, lihat jawaban.)
Peter Cordes

6
Semua orang terus mengatakan "memotong ke nol" atau "langit-langit" atau "lantai" seperti kode membuat keputusan yang disengaja pada teknik yang akan digunakan. Jika kodenya bisa berbicara akan dikatakan"I just throw the dam fraction part in the trash and move on with life"
Timothy LJ Stewart

3
@ TimothyL.J.Stewart "kode" ini membuat keputusan yang disengaja. Sesuai spesifikasinya, divisi integer dimaksudkan sebagai divisi T (runcation). Karena itu, operator modulo / sisanya diimplemantasikan secara berbeda daripada jika menggunakan bahasa lain, misalnya, Python atau Ruby. Lihat ini untuk daftar berbagai cara bahasa melakukan operator modulo dan makalah ini yang mencantumkan setidaknya lima cara umum bahasa pemrograman memutuskan untuk melakukan div / modulo.
13steinj

1
@ 13steinj Saya berbicara bahasa sehari-hari per komentar itu berubah menjadi "itu terpotong menuju nol ... tidak itu lantai ... tidak jika itu negatif langit-langitnya ..." kadang-kadang teknis tidak menyebar ke masa depan dengan memori manusia seperti yang kita inginkan, tetapi mengetahui secara intuitif bahwa "bagian pecahan dibuang" Anda dapat memperoleh poin teknis. Teknisnya adalah beban yang berat, tetapi intuisi ringan dan menyegarkan seperti angin, saya akan membawanya jauh dan lebar dan bila perlu saya akan tahu harus mulai dari mana. Seperti kertas yang Anda tautkan, terima kasih.
Timothy LJ Stewart

Saya menjawab di sini dengan penekanan pada divisi Euclidean (permainan antara divisi integer dan operator modulus).
Picaud Vincent

Jawaban:


182

Apakah hasilnya akan selalu menjadi dasar divisi? Apa perilaku yang didefinisikan?

Ya, hasil bagi bilangan bulat dari dua operan.

6.5.5 Operator multiplikasi

6 Ketika bilangan bulat dibagi, hasil / operator adalah hasil bagi aljabar dengan setiap bagian pecahan dibuang. 88) Jika hasil bagi a / b dapat diwakili, ungkapan (a / b) * b + a% b harus sama dengan a.

dan catatan kaki yang sesuai:

88) Ini sering disebut '' pemotongan menuju nol ''.

Tentu saja dua hal yang perlu diperhatikan adalah:

3 Konversi aritmatika yang biasa dilakukan pada operan.

dan:

5 Hasil dari / operator adalah hasil bagi dari pembagian operan pertama oleh yang kedua; hasil dari operator% adalah sisanya. Dalam kedua operasi, jika nilai operan kedua adalah nol, perilaku tidak terdefinisi.

[Catatan: Tekankan milikku]


26
... kecuali, tentu saja, Anda membagi angka negatif dengan positif (atau vv), dalam hal ini akan menjadi langit-langit.
Will A

74
Ini bukan lantai atau langit-langit, ini adalah pemotongan bagian fraksional, berbeda secara konsep!
lornova

38
@ Will A: Tidak. Ini didefinisikan sebagai pemotongan menuju nol. Menyebutnya hal lain hanya akan menambah kebingungan jadi tolong jangan melakukannya.
Martin York

44
Setidaknya dari perspektif matematika, pemotongan ke nol sama dengan "jika> 0 maka lantai lagi langit-langit." Saya pikir hanya menyebutnya pemotongan lebih sederhana daripada menyebutnya lantai / langit-langit, tetapi keduanya valid. Apapun, poin Will A valid: Jawaban Dirkgently sebagian tidak benar, karena ia menyatakan bahwa OP benar tentang hasil yang menjadi dasar divisi.
Brian

9
@Philip Potter: Saya tidak berpikir itu didefinisikan dalam C89, dan itu tidak dalam standar C ++ 1998. Dalam hal itu, tentu saja (a / b) * b + a % b == aharus dipenuhi, dan nilai absolut dari a % bharus kurang dari a, tetapi apakah a % bnegatif untuk negatif aatau btidak ditentukan.
David Thornley

41

Dirkgently memberikan deskripsi yang sangat baik tentang divisi integer di C99, tetapi Anda juga harus tahu bahwa di divisi integer C89 dengan operan negatif memiliki arah implementasi yang ditentukan.

Dari draft ANSI C (3.3.5):

Jika salah satu operan negatif, apakah hasil dari operator / adalah bilangan bulat terbesar kurang dari hasil bagi aljabar atau bilangan bulat terkecil yang lebih besar dari hasil aljabar yang ditentukan implementasi, seperti tanda hasil dari% operator. Jika hasil bagi a / b dapat diwakili, ungkapan (a / b) * b + a% b harus sama dengan a.

Jadi hati-hati dengan angka negatif ketika Anda terjebak dengan kompiler C89.

Itu adalah fakta yang menyenangkan bahwa C99 memilih pemotongan ke nol karena itulah cara FORTRAN melakukannya. Lihat pesan ini di comp.std.c.


2
Dan C99 draft N1256 kata pengantar ayat 5 menyebutkan reliable integer divisionsebagai fitur bahasa baru. Luar biasa *-*.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Pemotongan adalah bagaimana perangkat keras CPU yang paling umum (misalnya x86) berperilaku, jadi itu gila untuk membuat pilihan yang berbeda. IDK yang lebih dulu, Fortran semantik atau perilaku perangkat keras, tapi itu bukan kebetulan bahwa mereka juga sama.
Peter Cordes

2
@PeterCordes: Perangkat keras CPU yang paling umum dapat melakukan pembagian lantai dengan konstanta yang lebih cepat daripada yang dapat dilakukan pemotongan divisi. IMHO, akan lebih baik bagi Standar untuk mengatakan itu expr1 / expr2dan expr1 % expr2harus konsisten satu sama lain ketika kedua contoh expr1menggabungkan objek yang sama dengan cara yang sama, dan juga untuk expr2, tetapi pilihan pemotongan divisi versus pembagian lantai dinyatakan tidak ditentukan. Itu akan memungkinkan pembuatan kode yang lebih efisien tanpa melanggar banyak kompatibilitas (dan implementasi dapat mendokumentasikan perilaku spesifik jika cenderung)
supercat

23

Di mana hasilnya negatif, C memotong ke arah 0 daripada lantai - Saya belajar bacaan tentang mengapa divisi integer Python selalu lantai di sini: Mengapa Lantai Divisi Integer Python


3
Saya setuju dengan komentar yang bertanya-tanya apakah pernah (negatif% pos) menjadi negatif pernah berguna? Pada catatan terkait, saya bertanya-tanya apakah perilaku aritmetika-salah yang diperlukan dalam beberapa kasus "unsignedvar> signedvar" pernah berguna? Saya dapat memahami alasan mengapa tidak membutuhkan perilaku yang selalu benar; Saya tidak melihat alasan untuk menuntut perilaku yang salah.
supercat

8
+1 untuk referensi yang bagus tentang mengapa flooring adalah perilaku yang benar untuk pembagian integer (bertentangan dengan definisi C, yang rusak dan hampir tidak pernah berguna).
R .. GitHub BERHENTI MEMBANTU ICE

@supercat Pertimbangkan:, filtered = (k - 1) * filtered + value + carry; carry = filtered % factor; filtered /= factordiulangi dengan perubahan nilai value. Itu membuat pendekatan integer yang bagus untuk filter lowpass orde pertama dengan konstanta waktu k... tapi itu hanya simetris jika divisi memotong dan carrymendapatkan nilai negatif. Kedua perilaku untuk pembagian berguna dari waktu ke waktu.
hobbs

1
@obb: Saya tidak berpikir kode di atas akan berperilaku bersih ketika sinyal melewati nol. Jika divoperator divisi lantai dan factoraneh, maka filtered += (filter+(factor div 2)) div factorakan menghasilkan perilaku bersih dan simetris untuk semua nilai hingga INT_MAX-(factor div 2).
supercat

@supercat tidak berfungsi; kode itu hanya sedikit suling dari sesuatu yang saya miliki berjalan di pengontrol jam atom untuk sementara waktu.
hobbs

21

Ya, hasilnya selalu terpotong ke nol. Ini akan membulatkan ke arah nilai absolut terkecil.

-5 / 2 = -2
 5 / 2 =  2

Untuk nilai yang ditandatangani tidak ditandatangani dan tidak negatif, ini sama dengan lantai (pembulatan menuju -Infinity).


43
Pemotongan, bukan lantai.
dan04

9
@ dan04: lantai ya hanya akan berlaku untuk bilangan bulat positif :)
Leonid

13

Apakah hasilnya akan selalu menjadi dasar divisi?

Tidak. Hasilnya bervariasi, tetapi variasi hanya terjadi untuk nilai negatif.

Apa perilaku yang didefinisikan?

Untuk membuatnya jelas putaran lantai menuju infinity negatif, sedangkan putaran divisi integer menuju nol (terpotong)

Untuk nilai positif, keduanya sama

int integerDivisionResultPositive= 125/100;//= 1
double flooringResultPositive= floor(125.0/100.0);//=1.0

Untuk nilai negatif ini berbeda

int integerDivisionResultNegative= -125/100;//=-1
double flooringResultNegative= floor(-125.0/100.0);//=-2.0

0

Saya tahu orang-orang telah menjawab pertanyaan Anda tetapi dalam istilah awam:

5 / 2 = 2 // karena keduanya 5 dan 2 adalah bilangan bulat dan divisi bilangan bulat selalu memotong desimal

5.0 / 2 or 5 / 2.0 or 5.0 /2.0 = 2.5 // di sini 5 atau 2 atau keduanya memiliki desimal maka hasil bagi Anda akan mendapatkan dalam desimal.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.