Diberikan nilai integer x
dan y
, C dan C ++ keduanya kembali sebagai hasil bagi q = x/y
lantai dari titik mengambang yang setara. Saya tertarik pada metode mengembalikan langit-langit sebagai gantinya. Sebagai contoh, ceil(10/5)=2
dan ceil(11/5)=3
.
Pendekatan yang jelas melibatkan sesuatu seperti:
q = x / y;
if (q * y < x) ++q;
Ini membutuhkan perbandingan dan penggandaan ekstra; dan metode lain yang pernah saya lihat (sebenarnya digunakan) melibatkan casting sebagai a float
atau double
. Apakah ada metode yang lebih langsung yang menghindari multiplikasi tambahan (atau divisi kedua) dan cabang, dan itu juga menghindari casting sebagai angka floating point?
q = x/y + (x % y != 0);
cukup sajaJawaban:
Untuk angka positif
Untuk mengumpulkan ...
atau (menghindari overflow dalam x + y)
sumber
x/y
juga langit-langit divisi. C90 tidak menentukan cara membulatkan, dan saya pikir standar C ++ saat ini juga tidak.q = x / y;
Untuk angka positif:
sumber
Jawaban Sparky adalah salah satu cara standar untuk mengatasi masalah ini, tetapi seperti yang saya juga tulis dalam komentar saya, Anda berisiko meluap. Ini dapat diselesaikan dengan menggunakan tipe yang lebih luas, tetapi bagaimana jika Anda ingin membagi
long long
s?Jawaban Nathan Ernst memberikan satu solusi, tetapi melibatkan pemanggilan fungsi, deklarasi variabel dan kondisional, yang membuatnya tidak lebih pendek dari kode OP dan bahkan mungkin lebih lambat, karena lebih sulit untuk dioptimalkan.
Solusi saya adalah ini:
Ini akan sedikit lebih cepat daripada kode OP, karena modulo dan divisi dilakukan dengan menggunakan instruksi yang sama pada prosesor, karena kompiler dapat melihat bahwa mereka setara. Setidaknya gcc 4.4.1 melakukan optimasi ini dengan flag -O2 pada x86.
Secara teori, kompiler mungkin menyejajarkan fungsi memanggil kode Nathan Ernst dan memancarkan hal yang sama, tetapi gcc tidak melakukan itu ketika saya mengujinya. Ini mungkin karena itu akan mengikat kode yang dikompilasi ke versi tunggal dari perpustakaan standar.
Sebagai catatan terakhir, semua ini tidak penting pada mesin modern, kecuali jika Anda berada dalam loop yang sangat ketat dan semua data Anda ada di register atau L1-cache. Kalau tidak, semua solusi ini akan sama cepatnya, kecuali kemungkinan Nathan Ernst, yang mungkin lebih lambat secara signifikan jika fungsinya diambil dari memori utama.
sumber
q = (x > 0)? 1 + (x - 1)/y: (x / y);
q = x / y + (x % y > 0);
apakah lebih mudah daripada? :
ekspresi?Anda bisa menggunakan
div
fungsi di cstdlib untuk mendapatkan hasil bagi & sisa dalam satu panggilan dan kemudian menangani langit-langit secara terpisah, seperti di bawah inisumber
return res.quot + !!res.rem;
:)Bagaimana dengan ini? (membutuhkan y non-negatif, jadi jangan gunakan ini dalam kasus langka di mana y adalah variabel tanpa jaminan non-negatif)
Saya mengurangi
y/y
menjadi satu, menghilangkan istilahx + y - 1
dan dengan itu kemungkinan meluap.Saya menghindari
x - 1
membungkus ketikax
adalah tipe unsigned dan berisi nol.Untuk yang ditandatangani
x
, negatif dan nol masih bergabung menjadi satu wadah.Mungkin bukan manfaat besar pada CPU serba guna modern, tetapi ini akan jauh lebih cepat dalam sistem embedded daripada jawaban yang benar lainnya.
sumber
Ada solusi untuk positif dan negatif
x
tetapi hanya untuk positify
dengan hanya 1 divisi dan tanpa cabang:Catatan, jika
x
positif maka pembagian adalah menuju nol, dan kita harus menambahkan 1 jika pengingat bukan nol.Jika
x
negatif maka pembagian menuju nol, itulah yang kami butuhkan, dan kami tidak akan menambahkan apa pun karenax % y
tidak positifsumber
Ini berfungsi untuk angka positif atau negatif:
Jika ada sisa, periksa untuk melihat apakah
x
dany
dari tanda yang sama dan tambahkan1
sesuai.sumber
Saya lebih suka berkomentar tetapi saya tidak memiliki perwakilan yang cukup tinggi.
Sejauh yang saya ketahui, untuk argumen positif dan pembagi yang merupakan kekuatan 2, ini adalah cara tercepat (diuji dalam CUDA):
Hanya untuk argumen positif umum, saya cenderung melakukannya seperti ini:
sumber
q = x/y + !!(x % y);
menghadapiq = x/y + (x % y == 0);
danq = (x + y - 1) / y;
solusi kinerja bijaksana dalam CUDA kontemporer.bentuk generik yang disederhanakan,
Untuk jawaban yang lebih umum, C ++ berfungsi untuk divisi integer dengan strategi pembulatan yang terdefinisi dengan baik
sumber
Kompilasi dengan O3, Kompiler melakukan optimasi dengan baik.
sumber