Saya perlu membuat angka acak dalam interval tertentu, [max; min].
Selain itu, bilangan acak harus didistribusikan secara seragam selama interval, tidak ditempatkan ke titik tertentu.
Saat ini saya menghasilkan sebagai:
for(int i=0; i<6; i++)
{
DWORD random = rand()%(max-min+1) + min;
}
Dari pengujian saya, angka acak dihasilkan di sekitar satu titik saja.
Example
min = 3604607;
max = 7654607;
Nomor acak dihasilkan:
3631594
3609293
3630000
3628441
3636376
3621404
Dari jawaban di bawah ini: OK, RAND_MAX adalah 32767. Saya menggunakan platform C ++ Windows. Apakah ada metode lain untuk menghasilkan bilangan acak dengan distribusi seragam?
rand()
seragam. Perpustakaan mana yang Anda gunakan?cstdlib.h
'srand()
TIDAK seragam: cplusplus.com/reference/cstdlib/randJawaban:
Mengapa
rand
ide yang burukSebagian besar jawaban yang Anda dapatkan di sini menggunakan
rand
fungsi dan operator modulus. Metode itu mungkin tidak menghasilkan angka secara seragam (tergantung pada kisaran dan nilaiRAND_MAX
), dan karena itu tidak disarankan.C ++ 11 dan generasi di atas rentang
Dengan C ++ 11 beberapa opsi lain telah meningkat. Salah satu yang sesuai dengan kebutuhan Anda, untuk menghasilkan nomor acak dalam suatu range, cukup baik:
std::uniform_int_distribution
. Berikut contohnya:const int range_from = 0; const int range_to = 10; std::random_device rand_dev; std::mt19937 generator(rand_dev()); std::uniform_int_distribution<int> distr(range_from, range_to); std::cout << distr(generator) << '\n';
Dan inilah contoh berjalannya.
Generator acak lainnya
The
<random>
sundulan menawarkan tak terhitung generator nomor acak lain dengan berbagai jenis distribusi termasuk Bernoulli, Poisson dan normal.Bagaimana cara mengocok wadah?
Standar menyediakan
std::shuffle
, yang dapat digunakan sebagai berikut:std::vector<int> vec = {4, 8, 15, 16, 23, 42}; std::random_device random_dev; std::mt19937 generator(random_dev()); std::shuffle(vec.begin(), vec.end(), generator);
Algoritme akan menyusun ulang elemen secara acak, dengan kompleksitas linier.
Boost.Random
Alternatif lain, jika Anda tidak memiliki akses ke kompiler C ++ 11 +, adalah menggunakan Boost.Random . Antarmukanya sangat mirip dengan C ++ 11.
sumber
mt19937
tipe?1 9 6 2 8 7 1 4 7 7
,. Apakah Anda cara mengacak ini setiap kali kami menjalankan program?[Sunting] Peringatan: Jangan gunakan
rand()
untuk statistik, simulasi, kriptografi atau apapun yang serius.Cukup bagus untuk membuat angka-angka terlihat acak untuk manusia biasa yang sedang terburu-buru, tidak lebih.
Lihat balasan @ Jefffrey untuk opsi yang lebih baik, atau jawaban untuk nomor acak aman-kripto ini.
Umumnya, bit tinggi menunjukkan distribusi yang lebih baik daripada bit rendah, jadi cara yang disarankan untuk menghasilkan angka acak dari rentang untuk tujuan sederhana adalah:
((double) rand() / (RAND_MAX+1)) * (max-min+1) + min
Catatan : pastikan RAND_MAX + 1 tidak meluap (terima kasih Demi)!
Pembagian menghasilkan nomor acak dalam interval [0, 1); "rentangkan" ini ke kisaran yang diperlukan. Hanya ketika max-min + 1 mendekati RAND_MAX Anda memerlukan fungsi "BigRand ()" seperti yang diposting oleh Mark Ransom.
Ini juga menghindari beberapa masalah pemotongan karena modulo, yang dapat memperburuk angka Anda lebih jauh.
Pembuat nomor acak bawaan tidak dijamin memiliki kualitas yang diperlukan untuk simulasi statistik. Bilangan boleh saja "terlihat acak" bagi manusia, tetapi untuk aplikasi yang serius, Anda harus mengambil sesuatu yang lebih baik - atau setidaknya memeriksa propertinya (distribusi seragam biasanya bagus, tetapi nilai cenderung berkorelasi, dan urutannya deterministik ). Knuth memiliki risalah yang sangat baik (jika sulit dibaca) tentang generator bilangan acak, dan saya baru-baru ini menemukan LFSR sangat bagus dan sangat mudah diimplementasikan, mengingat propertinya OK untuk Anda.
sumber
( rand() / ((double)RAND_MAX+1)) * (max-min+1) + min
Cukup pindahkan konversi menjadi dua kali lipat dan hindari masalah.Saya ingin melengkapi jawaban Angry Shoe dan peterchen yang sangat baik dengan gambaran singkat tentang keadaan seni pada tahun 2015:
Beberapa pilihan bagus
randutils
The
randutils
library (presentasi) merupakan hal baru yang menarik, menawarkan antarmuka yang sederhana dan (dinyatakan) yang kuat kemampuan random. Ini memiliki kelemahan yang menambah ketergantungan pada proyek Anda dan, karena masih baru, itu belum diuji secara ekstensif. Bagaimanapun, karena gratis (lisensi MIT) dan hanya header, saya pikir itu patut dicoba.Sampel minimal: die roll
#include <iostream> #include "randutils.hpp" int main() { randutils::mt19937_rng rng; std::cout << rng.uniform(1,6) << "\n"; }
Bahkan jika seseorang tidak tertarik dengan perpustakaan, situs web ( http://www.pcg-random.org/ ) menyediakan banyak artikel menarik tentang tema pembuatan bilangan acak secara umum dan perpustakaan C ++ pada khususnya.
Boost.Random
Boost.Random
(dokumentasi) adalah perpustakaan yang terinspirasiC++11
's<random>
, dengan siapa saham banyak antarmuka. Sementara secara teoritis juga menjadi ketergantungan eksternal,Boost
sekarang memiliki status perpustakaan "kuasi-standar", danRandom
modulnya dapat dianggap sebagai pilihan klasik untuk pembuatan bilangan acak berkualitas baik. Ini menampilkan dua keuntungan sehubungan denganC++11
solusi:random_device
metode penggunaan sistem yang tawaran pembenihan berkualitas baikSatu-satunya kelemahan kecil adalah bahwa penawaran modul
random_device
tidak hanya untuk header, seseorang harus mengkompilasi dan menautkanboost_random
.Sampel minimal: die roll
#include <iostream> #include <boost/random.hpp> #include <boost/nondet_random.hpp> int main() { boost::random::random_device rand_dev; boost::random::mt19937 generator(rand_dev()); boost::random::uniform_int_distribution<> distr(1, 6); std::cout << distr(generator) << '\n'; }
Sementara sampel minimal bekerja dengan baik, program nyata harus menggunakan sepasang perbaikan:
mt19937
sebuahthread_local
: generator cukup gemuk (> 2 KB) dan lebih baik tidak dialokasikan pada stackmt19937
dengan lebih dari satu bilangan bulat: Mersenne Twister memiliki status yang besar dan dapat memanfaatkan lebih banyak entropi selama inisialisasiBeberapa pilihan yang tidak terlalu bagus
Pustaka C ++ 11
Meskipun menjadi solusi yang paling idiomatis,
<random>
perpustakaan tidak menawarkan banyak imbalan atas kompleksitas antarmukanya bahkan untuk kebutuhan dasar. Kekurangannya adalahstd::random_device
: Standar tidak mengamanatkan kualitas minimal apa pun untuk keluarannya (selamaentropy()
pengembalian0
) dan, mulai 2015, MinGW (bukan kompiler yang paling sering digunakan, tetapi bukan pilihan esoteris) akan selalu mencetak4
pada sampel minimal.Sampel minimal: die roll
#include <iostream> #include <random> int main() { std::random_device rand_dev; std::mt19937 generator(rand_dev()); std::uniform_int_distribution<int> distr(1, 6); std::cout << distr(generator) << '\n'; }
Jika implementasinya tidak busuk, solusi ini harus setara dengan Boost, dan saran yang sama berlaku.
Solusi Godot
Sampel minimal: die roll
#include <iostream> #include <random> int main() { std::cout << std::randint(1,6); }
Ini adalah solusi yang sederhana, efektif dan rapi. Hanya cacat, perlu beberapa saat untuk mengkompilasi - sekitar dua tahun, asalkan C ++ 17 dirilis tepat waktu dan
randint
fungsi eksperimental disetujui ke dalam Standar baru. Mungkin pada saat itu juga jaminan kualitas pembenihan akan meningkat.The buruk-adalah-baik solusi
Sampel minimal: die roll
#include <cstdlib> #include <ctime> #include <iostream> int main() { std::srand(std::time(nullptr)); std::cout << (std::rand() % 6 + 1); }
Solusi C lama dianggap berbahaya, dan untuk alasan yang baik (lihat jawaban lain di sini atau analisis terperinci ini ). Namun, ia memiliki kelebihan: sederhana, portabel, cepat dan jujur, dalam arti diketahui bahwa nomor acak yang didapat hampir tidak layak, dan oleh karena itu orang tidak tergoda untuk menggunakannya untuk tujuan yang serius.
Solusi troll akuntansi
Sampel minimal: die roll
#include <iostream> int main() { std::cout << 9; // http://dilbert.com/strip/2001-10-25 }
Sementara 9 adalah hasil yang agak tidak biasa untuk die roll biasa, seseorang harus mengagumi kombinasi kualitas yang sangat baik dalam solusi ini, yang berhasil menjadi yang tercepat, paling sederhana, paling ramah-cache dan paling portabel. Dengan mengganti 9 dengan 4 seseorang mendapatkan generator yang sempurna untuk semua jenis Dungeons and Dragons yang mati, sambil tetap menghindari nilai sarat simbol 1, 2 dan 3. Satu-satunya kekurangan kecil adalah, karena temperamen buruk troll akuntansi Dilbert, program ini sebenarnya menimbulkan perilaku yang tidak terdefinisi.
sumber
randutils
perpustakaan disebut PCG sekarang.Jika
RAND_MAX
32767, Anda dapat menggandakan jumlah bit dengan mudah.int BigRand() { assert(INT_MAX/(RAND_MAX+1) > RAND_MAX); return rand() * (RAND_MAX+1) + rand(); }
sumber
rand
panggilan pertama kembali0x1234
dan kedua0x5678
, maka Anda mendapatkan0x12345678
. Itulah satu - satunya nomor yang bisa Anda dapatkan yang dimulai dengan0x1234
, karena nomor berikutnya akan selalu0x5678
. Anda mendapatkan hasil 32-bit, tetapi Anda hanya memiliki 32768 kemungkinan nomor.Jika Anda bisa, gunakan Boost . Saya sangat beruntung dengan perpustakaan acak mereka .
uniform_int
harus melakukan apa yang kamu inginkan.sumber
uniform_int
saat itu. Sangat mudah untuk menghasilkan keluaran yang tidak bias, ada banyak pertanyaan di sini yang mendemonstrasikan metode tersebut.Jika Anda khawatir tentang keacakan dan bukan tentang kecepatan, Anda harus menggunakan metode pembuatan nomor acak yang aman. Ada beberapa cara untuk melakukan ini ... Yang termudah adalah dengan menggunakan Random Number Generator OpenSSL .
Anda juga dapat menulis sendiri menggunakan algoritma enkripsi (seperti AES ). Dengan memilih seed dan IV dan kemudian secara terus menerus mengenkripsi ulang output dari fungsi enkripsi. Menggunakan OpenSSL lebih mudah, tetapi kurang jantan.
sumber
Anda harus melihat
RAND_MAX
kompiler / lingkungan khusus Anda. Saya pikir Anda akan melihat hasil ini jikarand()
menghasilkan angka 16-bit acak. (Anda tampaknya mengasumsikan itu akan menjadi angka 32-bit).Saya tidak bisa menjanjikan ini adalah jawabannya, tapi tolong posting nilai Anda
RAND_MAX
, dan sedikit lebih detail tentang lingkungan Anda.sumber
Periksa apa yang
RAND_MAX
ada di sistem Anda - Saya rasa itu hanya 16 bit, dan jangkauan Anda terlalu besar untuk itu.Di luar itu, lihat diskusi ini tentang: Menghasilkan Bilangan Bulat Acak dalam Rentang yang Diinginkan dan catatan tentang penggunaan (atau tidak) fungsi C rand () .
sumber
Ini bukan kodenya, tetapi logika ini dapat membantu Anda.
static double rnd(void) { return (1.0 / (RAND_MAX + 1.0) * ((double)(rand())) ); } static void InitBetterRnd(unsigned int seed) { register int i; srand( seed ); for( i = 0; i < POOLSIZE; i++){ pool[i] = rnd(); } } // This function returns a number between 0 and 1 static double rnd0_1(void) { static int i = POOLSIZE-1; double r; i = (int)(POOLSIZE*pool[i]); r = pool[i]; pool[i] = rnd(); return (r); }
sumber
Jika Anda ingin bilangan didistribusikan secara seragam pada rentang, Anda harus memecah rentang menjadi beberapa bagian yang sama yang mewakili jumlah titik yang Anda butuhkan. Kemudian dapatkan nomor acak dengan min / max untuk setiap bagian.
Sebagai catatan lain, Anda mungkin tidak boleh menggunakan
rand()
karena tidak terlalu bagus dalam menghasilkan angka acak. Saya tidak tahu platform apa yang Anda jalankan, tetapi mungkin ada fungsi yang lebih baik yang dapat Anda panggilrandom()
.sumber
Ini harus memberikan distribusi seragam pada rentang
[low, high)
tanpa menggunakan pelampung, selama rentang keseluruhan kurang dari RAND_MAX.uint32_t rand_range_low(uint32_t low, uint32_t high) { uint32_t val; // only for 0 < range <= RAND_MAX assert(low < high); assert(high - low <= RAND_MAX); uint32_t range = high-low; uint32_t scale = RAND_MAX/range; do { val = rand(); } while (val >= scale * range); // since scale is truncated, pick a new val until it's lower than scale*range return val/scale + low; }
dan untuk nilai yang lebih besar dari RAND_MAX Anda menginginkan sesuatu seperti
uint32_t rand_range(uint32_t low, uint32_t high) { assert(high>low); uint32_t val; uint32_t range = high-low; if (range < RAND_MAX) return rand_range_low(low, high); uint32_t scale = range/RAND_MAX; do { val = rand() + rand_range(0, scale) * RAND_MAX; // scale the initial range in RAND_MAX steps, then add an offset to get a uniform interval } while (val >= range); return val + low; }
Ini kira-kira bagaimana std :: uniform_int_distribution melakukan sesuatu.
sumber
Berdasarkan sifatnya, sampel kecil dari bilangan acak tidak harus didistribusikan secara seragam. Mereka acak. Saya setuju bahwa jika generator bilangan acak menghasilkan angka yang secara konsisten tampak dikelompokkan, mungkin ada yang salah dengannya.
Namun perlu diingat bahwa keacakan belum tentu seragam.
Edit: Saya menambahkan "sampel kecil" untuk memperjelas.
sumber
Solusi yang diberikan oleh man 3 rand untuk angka antara 1 dan 10 inklusif adalah:
j = 1 + (int) (10.0 * (rand() / (RAND_MAX + 1.0)));
Dalam kasus Anda, itu akan menjadi:
j = min + (int) ((max-min+1) * (rand() / (RAND_MAX + 1.0)));
Tentu saja, ini bukan keacakan atau keseragaman yang sempurna seperti yang ditunjukkan oleh beberapa pesan lain, tetapi ini cukup untuk sebagian besar kasus.
sumber
@Larutan
((double) rand() / (RAND_MAX+1)) * (max-min+1) + min
Peringatan : Jangan lupa karena peregangan dan kemungkinan kesalahan presisi (meskipun RAND_MAX cukup besar), Anda hanya dapat menghasilkan "bins" yang didistribusikan secara merata dan tidak semua angka dalam [min, maks].
@ Solusi: Bigrand
Peringatan : Perhatikan bahwa ini menggandakan bit, tetapi tetap tidak dapat menghasilkan semua angka dalam rentang Anda secara umum, yaitu, belum tentu benar bahwa BigRand () akan menghasilkan semua angka di antara dalam rentangnya.
Info : Pendekatan Anda (modulo) "baik-baik saja" selama rentang rand () melebihi rentang interval dan rand () "seragam". Kesalahan paling banyak untuk angka maks - menit pertama adalah 1 / (RAND_MAX +1).
Juga, saya menyarankan untuk beralih ke paket acak baru e di C ++ 11 juga, yang menawarkan lebih banyak variasi implementasi daripada rand ().
sumber
Ini adalah solusi yang saya dapatkan:
#include "<stdlib.h>" int32_t RandomRange(int32_t min, int32_t max) { return (rand() * (max - min + 1) / (RAND_MAX + 1)) + min; }
Ini adalah solusi ember, secara konseptual mirip dengan solusi yang digunakan
rand() / RAND_MAX
untuk mendapatkan kisaran floating point antara 0-1 dan kemudian dibulatkan menjadi ember. Namun, ini menggunakan matematika murni bilangan bulat, dan memanfaatkan lantai pembagian bilangan bulat untuk membulatkan nilai ke keranjang terdekat.Itu membuat beberapa asumsi. Pertama, ini mengasumsikan bahwa
RAND_MAX * (max - min + 1)
akan selalu sesuai dengan fileint32_t
. JikaRAND_MAX
32767 dan perhitungan int 32 bit digunakan, kisaran maksimum yang dapat Anda miliki adalah 32767. Jika implementasi Anda memiliki RAND_MAX yang jauh lebih besar, Anda dapat mengatasinya dengan menggunakan bilangan bulat yang lebih besar (sepertiint64_t
) untuk penghitungan. Kedua, jikaint64_t
digunakan tetapiRAND_MAX
masih 32767, pada kisaran yang lebih besar dariRAND_MAX
Anda akan mulai mendapatkan "lubang" di nomor keluaran yang mungkin. Ini mungkin masalah terbesar dengan solusi apa pun yang berasal dari penskalaanrand()
.Namun pengujian pada sejumlah besar iterasi menunjukkan metode ini sangat seragam untuk rentang kecil. Namun, ada kemungkinan (dan kemungkinan) bahwa secara matematis ini memiliki beberapa bias kecil dan mungkin mengembangkan masalah ketika kisaran tersebut mendekat
RAND_MAX
. Uji sendiri dan putuskan apakah itu memenuhi kebutuhan Anda.sumber
Tentu saja, kode berikut tidak akan memberi Anda nomor acak tetapi nomor acak semu. Gunakan kode berikut
#define QUICK_RAND(m,n) m + ( std::rand() % ( (n) - (m) + 1 ) )
Sebagai contoh:
int myRand = QUICK_RAND(10, 20);
Anda harus menelepon
srand(time(0)); // Initialize random number generator.
jika tidak, jumlahnya tidak akan mendekati acak.
sumber
Saya baru saja menemukan ini di Internet. Ini harus bekerja:
DWORD random = ((min) + rand()/(RAND_MAX + 1.0) * ((max) - (min) + 1));
sumber