Apakah saya melewatkan sesuatu? y / x + 1 berfungsi dengan baik (asalkan Anda tahu operator selalu membulatkan ke bawah).
rikkit
51
@rikkit - jika y dan x sama, y / x + 1 terlalu tinggi.
Ian Nelson
1
Bagi siapa saja yang baru saja menemukan ini, jawaban untuk pertanyaan dupe ini menghindari konversi yang tidak perlu menjadi dua kali lipat dan menghindari masalah yang meluap selain memberikan penjelasan yang jelas.
ZX9
2
@IanNelson lebih umum jika xhabis dibagi y, y/x + 1akan menjadi terlalu tinggi.
Ohad Schneider
1
@ ZX9 Tidak, itu tidak menghindari kekhawatiran meluap. Ini persis solusi yang sama seperti yang diposkan Ian Nelson di sini.
user247702
Jawaban:
478
Menemukan solusi yang elegan:
int pageCount =(records + recordsPerPage -1)/ recordsPerPage;
-1 karena bug overflow yang ditunjukkan oleh Brandon DuRette
finnw
30
Mr Obvious mengatakan: Ingatlah untuk memastikan bahwa recordsPerPage tidak nol
Adam Gent
7
Kerja bagus, saya tidak percaya C # tidak memiliki langit-langit integer.
gosukiwi
2
Yup, saya di sini pada pertengahan 2017 menemukan jawaban hebat ini setelah mencoba beberapa pendekatan yang jauh lebih kompleks.
Mifo
1
Untuk bahasa dengan operator divisi Euclidian yang tepat seperti Python, pendekatan yang lebih sederhana adalah pageCount = -((-records) // recordsPerPage).
supercat
194
Mengubah ke floating point dan kembali sepertinya sangat membuang waktu di level CPU.
Solusi Ian Nelson:
int pageCount =(records + recordsPerPage -1)/ recordsPerPage;
Dapat disederhanakan untuk:
int pageCount =(records -1)/ recordsPerPage +1;
AFAICS, ini tidak memiliki bug overflow yang ditunjukkan Brandon DuRette, dan karena itu hanya menggunakannya sekali, Anda tidak perlu menyimpan recordsPerPage khusus jika itu berasal dari fungsi yang mahal untuk mengambil nilai dari file konfigurasi atau sesuatu.
Yaitu ini mungkin tidak efisien, jika config.fetch_value menggunakan pencarian basis data atau sesuatu:
int pageCount =(records + config.fetch_value('records per page')-1)/ config.fetch_value('records per page');
Ini menciptakan variabel yang tidak benar-benar Anda butuhkan, yang mungkin memiliki implikasi memori (kecil) dan terlalu banyak mengetik:
int recordsPerPage = config.fetch_value('records per page')int pageCount =(records + recordsPerPage -1)/ recordsPerPage;
Ini semua satu baris, dan hanya mengambil data satu kali:
int pageCount =(records -1)/ config.fetch_value('records per page')+1;
+1, masalah nol catatan masih menghasilkan 1 pageCount sebenarnya mudah, karena saya masih ingin 1 halaman, menunjukkan placeholder / baris palsu "tidak ada catatan yang cocok dengan kriteria Anda", membantu menghindari masalah "hitungan 0 halaman" dalam apa pun kontrol pagination yang Anda gunakan.
Timothy Walters
27
Ketahuilah bahwa kedua solusi tidak mengembalikan pageCount yang sama untuk nol catatan. Versi yang disederhanakan ini akan mengembalikan 1 pageCount untuk nol catatan, sedangkan versi Roland Backhouse mengembalikan 0 pageCount. Baik jika itu yang Anda inginkan, tetapi kedua persamaan tidak setara ketika dilakukan oleh divisi integer gaya C # / Java.
Ian Nelson
10
suntingan kecil untuk kejelasan bagi orang-orang yang memindai dan kehilangan bodma saat mengubah penyederhanaan dari solusi Nelson (seperti yang saya lakukan pertama kali!), penyederhanaan dengan tanda kurung adalah ... int pageCount = ((catatan - 1) / recordsPerPage) +1
dave heywood
1
Anda harus menambahkan tanda kurung ke versi yang disederhanakan sehingga tidak bergantung pada urutan operasi tertentu. yaitu, ((catatan - 1) / recordsPerPage) + 1.
Martin
1
@Ian, jawaban ini tidak selalu kembali 1. Hal ini dapat kembali 0 jika recordsPerPage Anda adalah "1" dan ada 0 catatan: -1 / 1 + 1 = 0. Meskipun itu bukan kejadian super umum, penting untuk diingat jika Anda mengizinkan pengguna menyesuaikan ukuran halaman. Jadi jangan izinkan pengguna memiliki ukuran halaman 1, periksa ukuran halaman, atau keduanya (mungkin lebih baik untuk menghindari perilaku yang tidak terduga).
Michael
81
Untuk C # solusinya adalah dengan melemparkan nilai-nilai ke ganda (seperti Math.Ceiling mengambil ganda):
int nPages =(int)Math.Ceiling((double)nItems /(double)nItemsPerPage);
Di java Anda harus melakukan hal yang sama dengan Math.ceil ().
mengapa jawaban ini sangat jauh ke bawah ketika op meminta C # secara eksplisit!
felickz
2
Anda juga perlu memberikan output intkarena Math.Ceilingmengembalikan a doubleatau decimal, tergantung pada tipe input.
DanM7
15
karena ini sangat tidak efisien
Zar Shardan
6
Mungkin tidak efisien tetapi sangat mudah dimengerti. Mengingat menghitung penghitungan halaman biasanya dilakukan sekali per permintaan, kehilangan kinerja tidak akan dapat diukur.
Jared Kells
1
Ini hampir tidak terbaca dari ini "(dividend + (pembagi - 1)) / pembagi;" juga lambat dan membutuhkan perpustakaan matematika.
bergulung
68
Ini akan memberi Anda apa yang Anda inginkan. Anda pasti ingin x item dibagi dengan item y per halaman, masalahnya adalah ketika angka tidak merata muncul, jadi jika ada halaman parsial kami juga ingin menambahkan satu halaman.
int x = number_of_items;int y = items_per_page;// with out libraryint pages = x/y +(x % y >0?1:0)// with libraryint pages =(int)Math.Ceiling((double)x /(double)y);
x / y + !! (x% y) menghindari cabang untuk bahasa C-like. Kemungkinannya bagus, namun, kompiler Anda tetap melakukan itu.
Rhys Ulerich
2
1 untuk tidak meluap seperti jawaban di atas ... meskipun mengubah int menjadi dua kali lipat hanya untuk Math.ceiling dan kemudian kembali lagi adalah ide yang buruk dalam kode sensitif kinerja.
Cogwheel
3
@RhysUlerich yang tidak berfungsi di c # (tidak bisa langsung mengkonversi int ke bool). solusi rjmunro adalah satu-satunya cara untuk menghindari percabangan saya pikir.
smead
18
Solusi matematika integer yang disediakan Ian bagus, tetapi menderita bug integer overflow. Dengan asumsi semua variabel int, solusinya dapat ditulis ulang untuk menggunakan longmatematika dan menghindari bug:
int pageCount = (-1L + records + recordsPerPage) / recordsPerPage;
Jika recordsa long, bug tetap ada. Solusi modulus tidak memiliki bug.
@finnw: AFAICS, tidak ada contoh dunia nyata di halaman itu, hanya laporan orang lain yang menemukan bug dalam skenario teoretis.
rjmunro
5
Ya, saya menjadi jago dalam menunjukkan bug. Banyak bug dapat ada selamanya tanpa pernah menyebabkan masalah. Bug dengan bentuk yang sama ada dalam implementasi binarySearch JDK selama sekitar sembilan tahun, sebelum seseorang melaporkannya ( googleresearch.blogspot.com/2006/06/... ). Saya kira pertanyaannya adalah, terlepas dari seberapa tidak mungkin Anda menemukan bug ini, mengapa tidak memperbaikinya di muka?
Brandon DuRette
4
Juga, perlu dicatat bahwa itu bukan hanya jumlah elemen yang dihadirkan dalam hal ini, tetapi juga ukuran halaman. Jadi, jika Anda sedang membangun perpustakaan dan seseorang memilih untuk tidak halaman dengan melewati 2 ^ 31-1 (Integer.MAX_VALUE) sebagai ukuran halaman, maka bug dipicu.
int q = records / recordsPerPage, r = records % recordsPerPage;int pageCount = q -(-r >>(Integer.SIZE -1));
Catatan: (-r >> (Integer.SIZE - 1))terdiri dari bit tanda r, diulang 32 kali (terima kasih untuk menandatangani ekstensi >>operator.) Ini mengevaluasi ke 0 jika rnol atau negatif, -1 jika rpositif. Jadi mengurangi itu dari qefek menambahkan 1 jika records % recordsPerPage > 0.
Untuk catatan == 0, solusi rjmunro memberikan 1. Solusi yang benar adalah 0. Yang mengatakan, jika Anda tahu bahwa catatan> 0 (dan saya yakin kita semua mengasumsikan recordsPerPage> 0), maka solusi rjmunro memberikan hasil yang benar dan tidak memiliki masalah luapan.
int pageCount =0;if(records >0){
pageCount =(((records -1)/ recordsPerPage)+1);}// no else required
Semua solusi bilangan bulat matematika akan menjadi lebih efisien daripada salah satu solusi floating point.
Tidak ada pemeriksaan di sini (meluap, DivideByZero dll), jangan ragu untuk menambahkan jika Anda suka. Ngomong-ngomong, bagi mereka yang khawatir tentang overhead doa metode, fungsi-fungsi sederhana seperti ini mungkin digarisbawahi oleh kompiler, jadi saya tidak berpikir di situlah yang harus diperhatikan. Bersulang.
NB, Anda mungkin perlu menyadari hal ini juga (ada sisanya):
int remainder;int result =Math.DivRem(dividend, divisor,out remainder);
Ini salah. Sebagai contoh: DivideUp(4, -2)mengembalikan 0 (harus -2). Itu hanya benar untuk bilangan bulat non-negatif yang tidak jelas dari jawaban atau dari antarmuka fungsi.
Thash
6
Thash, mengapa Anda tidak melakukan sesuatu yang berguna seperti menambahkan sedikit cek tambahan kemudian jika jumlahnya negatif, bukannya memilih jawaban saya, dan salah membuat pernyataan selimut: "Ini tidak benar," padahal sebenarnya itu hanya keunggulan kasus. Saya sudah menjelaskan Anda harus melakukan pemeriksaan lain terlebih dahulu: "Tidak ada cek di sini (melimpah, DivideByZero, dll), jangan ragu untuk menambahkan jika Anda mau ."
Nicholas Petersen
1
Pertanyaan itu menyebutkan "Saya sedang memikirkan bagaimana cara menampilkan kontrol pagination " sehingga angka negatif akan keluar batas. Sekali lagi, lakukan saja sesuatu yang bermanfaat dan sarankan cek tambahan jika Anda mau, itu adalah upaya tim.
Nicholas Petersen
Saya tidak bermaksud bersikap kasar dan saya minta maaf jika Anda mengambilnya seperti itu. Pertanyaannya adalah "Bagaimana mengumpulkan hasil dari pembagian integer". Penulis menyebutkan pagination tetapi orang lain mungkin memiliki kebutuhan yang berbeda. Saya pikir akan lebih baik jika fungsi Anda entah bagaimana mencerminkan bahwa itu tidak berfungsi untuk bilangan bulat negatif karena tidak jelas dari antarmuka (misalnya nama atau jenis argumen yang berbeda). Untuk bekerja dengan bilangan bulat negatif, misalnya Anda dapat mengambil nilai absolut dari dividen dan pembagi dan mengalikan hasilnya dengan tandanya.
Thash
2
Alternatif lain adalah dengan menggunakan fungsi mod () (atau '%'). Jika ada sisa yang tidak nol, maka tambahlah hasil bilangan bulat dari divisi tersebut.
Berikut ini harus melakukan pembulatan yang lebih baik daripada solusi di atas, tetapi dengan mengorbankan kinerja (karena perhitungan floating point 0,5 * rctDenominator):
uint64_t integerDivide(constuint64_t& rctNumerator,constuint64_t& rctDenominator ){// Ensure .5 upwards is rounded up (otherwise integer division just truncates - ie gives no remainder)return(rctDenominator ==0)?0:(rctNumerator +(int)(0.5*rctDenominator))/ rctDenominator;}
x
habis dibagiy
,y/x + 1
akan menjadi terlalu tinggi.Jawaban:
Menemukan solusi yang elegan:
Sumber: Konversi Angka, Roland Backhouse, 2001
sumber
pageCount = -((-records) // recordsPerPage)
.Mengubah ke floating point dan kembali sepertinya sangat membuang waktu di level CPU.
Solusi Ian Nelson:
Dapat disederhanakan untuk:
AFAICS, ini tidak memiliki bug overflow yang ditunjukkan Brandon DuRette, dan karena itu hanya menggunakannya sekali, Anda tidak perlu menyimpan recordsPerPage khusus jika itu berasal dari fungsi yang mahal untuk mengambil nilai dari file konfigurasi atau sesuatu.
Yaitu ini mungkin tidak efisien, jika config.fetch_value menggunakan pencarian basis data atau sesuatu:
Ini menciptakan variabel yang tidak benar-benar Anda butuhkan, yang mungkin memiliki implikasi memori (kecil) dan terlalu banyak mengetik:
Ini semua satu baris, dan hanya mengambil data satu kali:
sumber
-1 / 1 + 1 = 0
. Meskipun itu bukan kejadian super umum, penting untuk diingat jika Anda mengizinkan pengguna menyesuaikan ukuran halaman. Jadi jangan izinkan pengguna memiliki ukuran halaman 1, periksa ukuran halaman, atau keduanya (mungkin lebih baik untuk menghindari perilaku yang tidak terduga).Untuk C # solusinya adalah dengan melemparkan nilai-nilai ke ganda (seperti Math.Ceiling mengambil ganda):
Di java Anda harus melakukan hal yang sama dengan Math.ceil ().
sumber
int
karenaMath.Ceiling
mengembalikan adouble
ataudecimal
, tergantung pada tipe input.Ini akan memberi Anda apa yang Anda inginkan. Anda pasti ingin x item dibagi dengan item y per halaman, masalahnya adalah ketika angka tidak merata muncul, jadi jika ada halaman parsial kami juga ingin menambahkan satu halaman.
sumber
Solusi matematika integer yang disediakan Ian bagus, tetapi menderita bug integer overflow. Dengan asumsi semua variabel
int
, solusinya dapat ditulis ulang untuk menggunakanlong
matematika dan menghindari bug:int pageCount = (-1L + records + recordsPerPage) / recordsPerPage;
Jika
records
along
, bug tetap ada. Solusi modulus tidak memiliki bug.sumber
Varian dari jawaban Nick Berardi yang menghindari cabang:
Catatan:
(-r >> (Integer.SIZE - 1))
terdiri dari bit tandar
, diulang 32 kali (terima kasih untuk menandatangani ekstensi>>
operator.) Ini mengevaluasi ke 0 jikar
nol atau negatif, -1 jikar
positif. Jadi mengurangi itu dariq
efek menambahkan 1 jikarecords % recordsPerPage > 0
.sumber
Untuk catatan == 0, solusi rjmunro memberikan 1. Solusi yang benar adalah 0. Yang mengatakan, jika Anda tahu bahwa catatan> 0 (dan saya yakin kita semua mengasumsikan recordsPerPage> 0), maka solusi rjmunro memberikan hasil yang benar dan tidak memiliki masalah luapan.
Semua solusi bilangan bulat matematika akan menjadi lebih efisien daripada salah satu solusi floating point.
sumber
Membutuhkan metode ekstensi:
Tidak ada pemeriksaan di sini (meluap,
DivideByZero
dll), jangan ragu untuk menambahkan jika Anda suka. Ngomong-ngomong, bagi mereka yang khawatir tentang overhead doa metode, fungsi-fungsi sederhana seperti ini mungkin digarisbawahi oleh kompiler, jadi saya tidak berpikir di situlah yang harus diperhatikan. Bersulang.NB, Anda mungkin perlu menyadari hal ini juga (ada sisanya):
sumber
DivideUp(4, -2)
mengembalikan 0 (harus -2). Itu hanya benar untuk bilangan bulat non-negatif yang tidak jelas dari jawaban atau dari antarmuka fungsi.Alternatif lain adalah dengan menggunakan fungsi mod () (atau '%'). Jika ada sisa yang tidak nol, maka tambahlah hasil bilangan bulat dari divisi tersebut.
sumber
Saya melakukan hal berikut, menangani setiap luapan:
Dan gunakan ekstensi ini untuk jika ada 0 hasil:
Juga, untuk nomor halaman saat ini (tidak ditanyakan tetapi dapat bermanfaat):
sumber
Alternatif untuk menghapus percabangan dalam pengujian untuk nol:
Tidak yakin apakah ini akan berfungsi dalam C #, harus dilakukan dalam C / C ++.
sumber
Metode generik, yang hasilnya dapat Anda ulangi mungkin menarik:
sumber
Lists.partition(List, int)
) dan ironisnyasize()
metode yang dihasilkanList
(padar09
) menderita bug melimpah yang disebutkan dalam jawaban Brandon DuRette .Saya memiliki kebutuhan serupa di mana saya perlu mengkonversi Menit menjadi jam & menit. Apa yang saya gunakan adalah:
sumber
Berikut ini harus melakukan pembulatan yang lebih baik daripada solusi di atas, tetapi dengan mengorbankan kinerja (karena perhitungan floating point 0,5 * rctDenominator):
sumber
Anda ingin melakukan pembagian floating point, dan kemudian menggunakan fungsi plafon, untuk mengumpulkan nilai ke integer berikutnya.
sumber