Hasilkan nomor acak secara seragam di seluruh rentang

94

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?

anand
sumber
2
Bangun Dice-O-Matic: gamesbyemail.com/News/DiceOMatic
Jarett Millard
1
Saya tidak tahu bahwa C ++ rand()seragam. Perpustakaan mana yang Anda gunakan? cstdlib.h's rand()TIDAK seragam: cplusplus.com/reference/cstdlib/rand
Mike Warren
3
Tidak, rand () seragam (kecuali di beberapa implementasi buggy awal). yang tidak seragam adalah menggunakan operator modulus '%' untuk membatasi jarak. Lihat stackoverflow.com/questions/2999075/… untuk solusi yang tepat, atau jika Anda memiliki 'arc4random_uniform' yang tersedia maka Anda juga dapat menggunakannya secara langsung.
John Meacham
@ Alien01: Apakah Anda mempertimbangkan untuk mengubah jawaban yang diterima menjadi jawaban dengan "Sepatu" ("Mengapa Rand adalah ide yang buruk" dll ..)? Jawaban saya benar-benar ketinggalan zaman dan setiap kali saya mendapat suara positif untuk itu, saya merasa seperti seseorang berlari ke lorong yang salah.
peterchen
Buku putih bagus tentang acak di c ++ 11.
Pupsik

Jawaban:

157

Mengapa randide yang buruk

Sebagian besar jawaban yang Anda dapatkan di sini menggunakan randfungsi dan operator modulus. Metode itu mungkin tidak menghasilkan angka secara seragam (tergantung pada kisaran dan nilai RAND_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.

Sepatu
sumber
24
PERHATIAN untuk jawaban ini, karena ini jauh lebih modern.
gsamaras
Ini jawaban yang benar. Terima kasih! Namun, saya ingin melihat deskripsi yang lebih mendalam dari setiap langkah kode itu. Misalnya apa itu mt19937tipe?
Apollo
@Apollo Dokumentasinya menyebutkan "32-bit Mersenne Twister oleh Matsumoto dan Nishimura, 1998". Saya berasumsi ini adalah algoritma untuk menghasilkan angka pseudo-random.
Sepatu
@Shoe, untuk rentang tertentu, itu menghasilkan angka dalam urutan yang sama 1 9 6 2 8 7 1 4 7 7,. Apakah Anda cara mengacak ini setiap kali kami menjalankan program?
1
@ Richard Apa alternatifnya?
Sepatu
60

[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.

peterchen
sumber
4
BigRand dapat memberikan hasil yang lebih baik meskipun rentang yang diinginkan tidak melebihi RAND_MAX. Pertimbangkan saat RAND_MAX adalah 32767 dan Anda menginginkan 32.767 kemungkinan nilai - dua dari 32.768 angka acak tersebut (termasuk nol) akan dipetakan ke keluaran yang sama, dan akan dua kali lebih mungkin muncul dibandingkan yang lain. Bukan properti acak yang ideal!
Tandai Tebusan
8
(RAND_MAX + 1) adalah ide yang buruk. Ini bisa berputar dan memberi Anda nilai negatif. Lebih baik melakukan sesuatu seperti: ((double) RAND_MAX) + 1.0
Demi
4
@peterchen: Saya pikir Anda salah paham tentang apa yang dikatakan demi. Maksudnya begini: ( rand() / ((double)RAND_MAX+1)) * (max-min+1) + min Cukup pindahkan konversi menjadi dua kali lipat dan hindari masalah.
Mooing Duck
3
Selain itu, ini hanya mengubah distribusi dari 32.767 nilai terbawah dalam rentang menjadi nilai 32.767 yang terdistribusi merata dalam rentang, dan nilai 4017233 yang tersisa tidak akan pernah dipilih oleh algoritme ini.
Mooing Duck
2
Jawaban yang diberikan adalah 1. Persamaan yang benar adalah: ((double) rand () / (RAND_MAX + 1.0)) * (max-min) + min "max-min + 1" digunakan saat menggunakan% bukan * . Anda akan melihat mengapa ketika Anda melakukan min = 0, max = 1. Bisakah peterchen atau @ peter-mortensen mengubahnya.
davepc
17

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 randutilslibrary (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 terinspirasi C++11's <random>, dengan siapa saham banyak antarmuka. Sementara secara teoritis juga menjadi ketergantungan eksternal, Boostsekarang memiliki status perpustakaan "kuasi-standar", dan Randommodulnya dapat dianggap sebagai pilihan klasik untuk pembuatan bilangan acak berkualitas baik. Ini menampilkan dua keuntungan sehubungan dengan C++11solusi:

  • ini lebih portabel, hanya membutuhkan dukungan kompiler untuk C ++ 03
  • nya random_devicemetode penggunaan sistem yang tawaran pembenihan berkualitas baik

Satu-satunya kelemahan kecil adalah bahwa penawaran modul random_devicetidak hanya untuk header, seseorang harus mengkompilasi dan menautkan boost_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:

  • membuat mt19937sebuah thread_local: generator cukup gemuk (> 2 KB) dan lebih baik tidak dialokasikan pada stack
  • benih mt19937dengan lebih dari satu bilangan bulat: Mersenne Twister memiliki status yang besar dan dapat memanfaatkan lebih banyak entropi selama inisialisasi

Beberapa 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 adalah std::random_device: Standar tidak mengamanatkan kualitas minimal apa pun untuk keluarannya (selama entropy()pengembalian 0) dan, mulai 2015, MinGW (bukan kompiler yang paling sering digunakan, tetapi bukan pilihan esoteris) akan selalu mencetak 4pada 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 randintfungsi 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.

Alberto M
sumber
The randutilsperpustakaan disebut PCG sekarang.
tay10r
10

Jika RAND_MAX32767, Anda dapat menggandakan jumlah bit dengan mudah.

int BigRand()
{
    assert(INT_MAX/(RAND_MAX+1) > RAND_MAX);
    return rand() * (RAND_MAX+1) + rand();
}
Mark Ransom
sumber
Saya tidak berpikir ini berhasil. Generator bilangan acak semu biasanya bersifat deterministik. Misalnya, jika randpanggilan pertama kembali 0x1234dan kedua 0x5678, maka Anda mendapatkan 0x12345678. Itulah satu - satunya nomor yang bisa Anda dapatkan yang dimulai dengan 0x1234, karena nomor berikutnya akan selalu 0x5678. Anda mendapatkan hasil 32-bit, tetapi Anda hanya memiliki 32768 kemungkinan nomor.
pengguna694733
@ user694733 generator nomor acak yang baik memiliki periode yang lebih besar dari jumlah keluaran yang dapat dihasilkannya, jadi 0x1234 tidak akan selalu diikuti oleh 0x5678.
Mark Ransom
9

Jika Anda bisa, gunakan Boost . Saya sangat beruntung dengan perpustakaan acak mereka .

uniform_int harus melakukan apa yang kamu inginkan.

Jeff Thomas
sumber
Saya telah melakukan beberapa pekerjaan pada uniform_int dengan twister merseinne dan sayangnya untuk rentang tertentu nilai yang dikembalikan oleh uniform_int tidak seragam seperti yang saya harapkan. Misalnya uniform_int <> (0, 3) cenderung menghasilkan lebih banyak 0 daripada 1 atau 2
ScaryAardvark
@ScaryAardvark kedengarannya seperti implementasi yang buruk uniform_intsaat itu. Sangat mudah untuk menghasilkan keluaran yang tidak bias, ada banyak pertanyaan di sini yang mendemonstrasikan metode tersebut.
Mark Ransom
@Tebusan. Ya, saya sepenuhnya setuju.
ScaryAardvark
8

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.

Kotak sabun
sumber
Saya tidak dapat menggunakan pustaka pihak ketiga? Saya dibatasi hanya untuk C ++.
anand
Kemudian lakukan rute jantan, terapkan AES atau algoritma enkripsi lainnya.
SoapBox
2
RC4 sepele untuk kode, dan cukup acak untuk semua tujuan praktis (kecuali WEP, tapi itu bukan sepenuhnya kesalahan RC4). Sungguh, itu kode yang sangat sepele. Seperti, 20 baris atau lebih. Entri Wikipedia memiliki pseudo-code.
Steve Jessop
4
Mengapa Anda tidak dapat menggunakan kode pihak ketiga? Jika ini adalah pertanyaan pekerjaan rumah, Anda harus menjawabnya, karena banyak orang lebih suka memberikan petunjuk yang berguna daripada memberikan solusi lengkap dalam kasus ini. Jika ini bukan pekerjaan rumah, tendang orang yang mengatakan "tidak ada kode pihak ke-3", karena dia bodoh.
DevSolar
Tautan lebih langsung ke dokumen fungsi OpenSSL rand (): openssl.org/docs/crypto/rand.html#
DevSolar
5

Anda harus melihat RAND_MAXkompiler / lingkungan khusus Anda. Saya pikir Anda akan melihat hasil ini jika rand()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.

abelenky
sumber
3

Periksa apa yang RAND_MAXada 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 () .

Rob Walker
sumber
Ok RAND_MAX adalah 32767. Saya menggunakan platform C ++ windows .. Apakah ada metode lain untuk menghasilkan nomor acak dengan distribusi seragam?
anand
2

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);
}
pengguna3503711
sumber
2

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 panggil random().

Jason Coco
sumber
1

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.

benf
sumber
0

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.

Kluge
sumber
"terdistribusi secara seragam" memiliki arti yang terdefinisi dengan baik, dan generator acak standar biasanya mendekati.
peterchen
Ya, Anda benar, generator bilangan acak harus menghasilkan keluaran yang seiring waktu umumnya seragam dalam distribusinya. Saya kira maksud saya adalah bahwa lebih dari sejumlah kecil contoh (6 seperti yang ditunjukkan pada contoh) output tidak selalu seragam.
Kluge
Kluge benar. Distribusi seragam dalam sampel kecil menunjukkan bahwa sampel tersebut jelas tidak acak.
Bill the Lizard
1
Bill, itu tidak menunjukkan hal seperti itu. Sampel kecil sebagian besar tidak berarti, tetapi jika RNG seharusnya seragam dan keluarannya seragam, mengapa hal itu lebih buruk daripada sampel kecil yang tidak seragam?
Dan Dyer
2
Distribusi signifikan dengan cara apa pun menunjukkan non-keacakan: Saya pikir Bill hanya berarti bahwa 6 hasil yang berjarak sama juga akan dicurigai. Dalam OP, 6 nilai berada pada kisaran 32k / 4M, atau <1% dari kisaran yang diinginkan. Kemungkinan ini menjadi positif palsu terlalu kecil untuk diperdebatkan.
Steve Jessop
0

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.

calandoa
sumber
1
Ini hanya mengatur ulang distribusi agar tampak lebih merata, tetapi sebenarnya tidak lebih bahkan untuk rentang yang besar (seperti kasus OP)
Mooing Duck
0

@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 ().

Ritualmaster
sumber
0

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_MAXuntuk 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 file int32_t. Jika RAND_MAX32767 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 (seperti int64_t) untuk penghitungan. Kedua, jika int64_tdigunakan tetapi RAND_MAXmasih 32767, pada kisaran yang lebih besar dari RAND_MAXAnda akan mulai mendapatkan "lubang" di nomor keluaran yang mungkin. Ini mungkin masalah terbesar dengan solusi apa pun yang berasal dari penskalaan rand().

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.

Ryan
sumber
-1

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.

Michael Haephrati
sumber
1
Pertanyaannya adalah meminta distribusi seragam. Solusi yang diusulkan ini tidak akan menghasilkan distribusi yang seragam. Library C ++ Standar memiliki fasilitas untuk pembuatan bilangan acak semu . Mereka melakukan menyediakan distribusi seragam, jika diminta.
IInspectable
-3

Saya baru saja menemukan ini di Internet. Ini harus bekerja:

DWORD random = ((min) + rand()/(RAND_MAX + 1.0) * ((max) - (min) + 1));
anand
sumber
Harap klarifikasi untuk apa Anda membutuhkannya, ada banyak algoritme untuk PRNG di luar sana. Selain itu, akan lebih mudah jika Anda mengedit pertanyaan utama daripada mengirim balasan.
peterchen
Ini bekerja paling baik untuk saya ... Saya bisa mendapatkan nomor acak terdistribusi lebih baik dengan rumus ini ..
anand
4
Jika rentang Anda melebihi RAND_MAX, hasilnya mungkin tidak seragam. Artinya, ada nilai dalam rentang yang tidak akan direpresentasikan tidak peduli berapa kali memanggil fungsi Anda.
dmckee --- kucing bekas moderator
4
Juga, jika max dan min keduanya unsigned int, dan min adalah 0, dan max adalah MAX_UINT, maka ((max) - (min) +1) akan menjadi 0, dan hasilnya akan selalu 0. Hati-hati terhadap luapan saat melakukan jenis matematika ini! Seperti dicatat oleh dmckee, ini memperluas distribusi pada rentang tujuan, tetapi tidak menjamin lebih dari nilai unik RAND_MAX.
jesup