Catatan : Jangan gunakan rand()untuk keamanan. Jika Anda memerlukan nomor yang aman secara kriptografis, lihat jawaban ini sebagai gantinya.
#include<time.h>#include<stdlib.h>
srand(time(NULL));// Initialization, should only be called once.int r = rand();// Returns a pseudo-random integer between 0 and RAND_MAX.
Sunting : Di Linux, Anda mungkin lebih suka menggunakan acak dan acak .
Memberi +1 untuk kesederhanaan, tetapi mungkin ide yang baik untuk menekankan bahwa srand () hanya boleh dipanggil satu kali . Juga, dalam aplikasi berulir, Anda mungkin ingin memastikan bahwa keadaan generator disimpan per utas, dan menaburkan generator satu kali untuk setiap utas.
RBerteig
41
@trusktr, ini rumit. Inilah alasannya: time()hanya berubah sekali per detik. Jika Anda memotong dari time(), untuk setiap panggilan rand(), maka Anda akan mendapatkan nilai yang sama untuk setiap panggilan selama satu detik. Tetapi alasan yang lebih besar adalah bahwa properti rand()dan fungsi seperti itu dikenal terbaik untuk use case di mana mereka diunggulkan tepat sekali per run, dan tidak pada setiap panggilan tunggal. Bergantung pada "keacakan" dengan properti yang belum diuji atau tidak terbukti menyebabkan masalah.
RBerteig
9
@trusktr untuk generator kongruensial linier sederhana (yang rand()biasanya adalah) penyemaian dengan cara rand()terbaik tidak akan berpengaruh sama sekali, dan paling buruk akan merusak kualitas generator yang diketahui. Ini adalah subjek yang mendalam. Mulailah dengan membaca Knuth Vol 2 Bab 3 pada angka acak sebagai pengantar terbaik untuk matematika dan perangkap.
RBerteig
21
Hindari peringatan kompiler dengan gips:srand((unsigned int)time(NULL));
GiovaMaster
9
Perlu diingat bahwa ini masih merupakan cara yang lemah untuk melihat PRNG. Baru tahun lalu, virus tipe cryptolocker di Linux membuat kesalahan dengan menyemai waktu, dan ini secara dramatis mengurangi ruang pencarian. Yang harus Anda lakukan adalah mendapatkan ide yang layak kapan infeksi terjadi dan kemudian coba benih dari sekitar waktu itu. Terakhir saya dengar, sumber keacakan yang terbaik adalah / dev / urandom, yang konon diunggulkan dari mashup sumber chaotic-ish seperti suhu pada perangkat keras. Namun, jika yang benar-benar Anda inginkan adalah agar program Anda bertindak berbeda pada setiap proses, solusi di atas baik-baik saja.
Jemenake
238
The rand()fungsi dalam <stdlib.h>pengembalian integer pseudo-acak antara 0 dan RAND_MAX. Anda bisa menggunakan srand(unsigned int seed)untuk mengatur seed.
Ini adalah praktik umum untuk menggunakan %operator bersamaan rand()untuk mendapatkan rentang yang berbeda (meskipun perlu diingat bahwa ini agak menghilangkan keseragaman). Sebagai contoh:
/* random int between 0 and 19 */int r = rand()%20;
Jika Anda benar-benar peduli tentang keseragaman, Anda dapat melakukan sesuatu seperti ini:
/* Returns an integer in the range [0, n).
*
* Uses rand(), and so is affected-by/affects the same seed.
*/int randint(int n){if((n -1)== RAND_MAX){return rand();}else{// Supporting larger values for n would requires an even more// elaborate implementation that combines multiple calls to rand()
assert (n <= RAND_MAX)// Chop off all of the values that would cause skew...int end = RAND_MAX / n;// truncate skew
assert (end >0);
end *= n;// ... and ignore results from rand() that fall above that limit.// (Worst case the loop condition should succeed 50% of the time,// so we can expect to bail out of this loop pretty quickly.)int r;while((r = rand())>= end);return r % n;}}
Ini adalah praktik umum yang baik-baik saja, tetapi bukan yang benar. Lihat ini dan ini .
Lazer
35
@ Lazer: Itu sebabnya saya berkata "meskipun perlu diingat bahwa ini agak menghilangkan keseragaman".
Laurence Gonsalves
3
@AbhimanyuAryan %Adalah operator modulus. Ini memberi Anda sisa dari divisi integer, jadi x % nakan selalu memberi Anda nomor di antara 0dan n - 1(selama xdan nkeduanya positif). Jika Anda masih merasa itu membingungkan, cobalah menulis sebuah program yang memiliki ihitungan dari 0 hingga 100, dan cetak i % nuntuk beberapa npilihan Anda yang lebih kecil dari 100.
Laurence Gonsalves
2
@necromancer Saya melanjutkan dan menambahkan solusi yang sangat seragam.
Laurence Gonsalves
2
@Lazer, tautan kedua yang Anda poskan sebenarnya masih belum seragam sempurna. Melakukan double dan back tidak membantu. Link pertama Anda diposting memiliki solusi sempurna seragam, meskipun itu akan loop banyak untuk batas atas kecil. Saya telah menambahkan solusi yang sangat seragam untuk jawaban ini yang seharusnya tidak berulang bahkan untuk batas atas kecil.
Laurence Gonsalves
53
Jika Anda memerlukan karakter atau integer acak yang aman:
Lebih luas, gunakan/dev/urandom , bukan /dev/random. Bukan OpenSSL (atau PRNGs userspace lainnya).
Sebagai contoh:
#include"sodium.h"int foo(){char myString[32];uint32_t myInt;if(sodium_init()<0){/* panic! the library couldn't be initialized, it is not safe to use */return1;}/* myString will be an array of 32 random bytes, not null-terminated */
randombytes_buf(myString,32);/* myInt will be a random number between 0 and 9 */
myInt = randombytes_uniform(10);}
randombytes_uniform() aman secara kriptografis dan tidak bias.
haruskah libsodium RNG diunggulkan sebelum memanggil randombytes_buf?
user2199593
Panggil saja sodium_init()di beberapa titik. Jangan khawatir tentang RNG, karena menggunakan kernel.
Scott Arciszewski
Catatan: Saya menyetujui hasil edit baru-baru ini sodium_init()walaupun itu belum tentu menjadi bagian dari contoh saya karena ini merupakan detail penting.
Scott Arciszewski
29
Mari kita pergi melalui ini. Pertama-tama kita menggunakan fungsi srand () untuk seed randomizer. Pada dasarnya, komputer dapat menghasilkan angka acak berdasarkan nomor yang diumpankan ke srand (). Jika Anda memberikan nilai seed yang sama, maka angka acak yang sama akan dihasilkan setiap waktu.
Oleh karena itu, kita harus menyemai randomizer dengan nilai yang selalu berubah. Kami melakukan ini dengan memberinya nilai waktu saat ini dengan fungsi time ().
Sekarang, ketika kita memanggil rand (), nomor acak baru akan dihasilkan setiap saat.
#include<stdio.h>int random_number(int min_num,int max_num);int main(void){
printf("Min : 1 Max : 40 %d\n", random_number(1,40));
printf("Min : 100 Max : 1000 %d\n",random_number(100,1000));return0;}int random_number(int min_num,int max_num){int result =0, low_num =0, hi_num =0;if(min_num < max_num){
low_num = min_num;
hi_num = max_num +1;// include max_num in output}else{
low_num = max_num +1;// include max_num in output
hi_num = min_num;}
srand(time(NULL));
result =(rand()%(hi_num - low_num))+ low_num;return result;}
Kode yang bagus, tetapi bukan ide yang baik untuk memanggil 'srand (waktu (NULL));'. metode ini menghasilkan angka yang sama ketika dipanggil dalam for loop.
RayOldProf
1
Pengeditan yang disarankan yang melibatkan kode sering ditolak. Seseorang membuat satu di sini dengan komentar "algoritma salah. Bisa menghasilkan angka lebih besar dari maksimum". Saya belum mengevaluasi klaim itu sendiri.
Martin Smith
1
Masalah @Martin Smith: 1) harus else{ low_num=max_num; hi_num=min_num+1;2) gagal saat hi_num - low_num > INT_MAX. 3) Menghilangkan nilai dalam situasi yang jarang terjadi INT_MAX > hi_num - low_num > RAND_MAX.
chux - Reinstate Monica
1
Mengembalikannya seperti ini akan menyebabkan fungsi ini menghasilkan angka yang sama jika dipanggil beberapa kali dalam detik yang sama. Jika Anda benar-benar ingin me-reseed, maka hanya me-reseed sekali per detik.
Élektra
1
Minor: hi_num = max_num + 1;tidak memiliki perlindungan terhadap luapan.
chux - Reinstate Monica
25
Jika Anda membutuhkan nomor acak semu yang lebih baik daripada yang stdlibdisediakan, periksa Mersenne Twister . Lebih cepat juga. Implementasi sampel berlimpah, misalnya di sini .
+1: Terlihat keren tapi saya baru saja membuat permainan menebak. Jika saya akan menggunakan generator nomor acak dalam aplikasi bisnis maka saya pasti akan menggunakan ini.
Kredns
4
Jangan gunakan Mersenne Twister, gunakan sesuatu yang bagus seperti xoroshiro128 + atau PCG. (Tautan yang relevan.)
Veedrac
17
Fungsi standar C adalah rand(). Cukup bagus untuk menangani kartu untuk solitaire, tapi itu mengerikan. Banyak implementasi rand()siklus melalui daftar angka pendek, dan bit rendah memiliki siklus yang lebih pendek. Cara beberapa program menyebutnya rand()mengerikan, dan menghitung benih yang baik untuk dilewatkan srand()adalah sulit.
Cara terbaik untuk menghasilkan angka acak dalam C adalah dengan menggunakan perpustakaan pihak ketiga seperti OpenSSL. Sebagai contoh,
#include<stdint.h>#include<stdio.h>#include<stdlib.h>#include<openssl/rand.h>/* Random integer in [0, limit) */unsignedint random_uint(unsignedint limit){union{unsignedint i;unsignedchar c[sizeof(unsignedint)];} u;do{if(!RAND_bytes(u.c,sizeof(u.c))){
fprintf(stderr,"Can't get random bytes!\n");
exit(1);}}while(u.i <(-limit % limit));/* u.i < (2**size % limit) */return u.i % limit;}/* Random double in [0.0, 1.0) */double random_double(){union{uint64_t i;unsignedchar c[sizeof(uint64_t)];} u;if(!RAND_bytes(u.c,sizeof(u.c))){
fprintf(stderr,"Can't get random bytes!\n");
exit(1);}/* 53 bits / 2**53 */return(u.i >>11)*(1.0/9007199254740992.0);}int main(){
printf("Dice: %d\n",(int)(random_uint(6)+1));
printf("Double: %f\n", random_double());return0;}
Mengapa begitu banyak kode? Bahasa lain seperti Java dan Ruby memiliki fungsi untuk bilangan bulat acak atau float. OpenSSL hanya memberikan byte acak, jadi saya mencoba untuk meniru bagaimana Java atau Ruby akan mengubahnya menjadi bilangan bulat atau mengapung.
Untuk bilangan bulat, kami ingin menghindari bias modulo . Misalkan kita mendapatkan beberapa bilangan bulat 4 digit acak rand() % 10000, tetapi rand()hanya dapat mengembalikan 0 hingga 32767 (seperti halnya di Microsoft Windows). Setiap angka dari 0 hingga 2767 akan muncul lebih sering daripada setiap angka dari 2768 hingga 9999. Untuk menghapus bias, kita dapat mencoba lagi rand()sementara nilainya di bawah 2768, karena nilai-nilai 30000 dari 2768 hingga 32767 memetakan secara seragam ke nilai 10000 dari 0 hingga 9999.
Untuk mengapung, kami ingin 53 bit acak, karena doublememegang 53 bit presisi (dengan asumsi itu adalah ganda IEEE). Jika kita menggunakan lebih dari 53 bit, kita mendapatkan bias pembulatan. Beberapa programmer menulis kode seperti rand() / (double)RAND_MAX, tetapi rand()mungkin mengembalikan hanya 31 bit, atau hanya 15 bit di Windows.
RAND_bytes()Benih OpenSSL sendiri, mungkin dengan membaca /dev/urandomdi Linux. Jika kita memerlukan banyak angka acak, akan terlalu lambat untuk membacanya /dev/urandom, karena mereka harus disalin dari kernel. Lebih cepat untuk memungkinkan OpenSSL menghasilkan lebih banyak angka acak dari sebuah seed.
Lebih lanjut tentang angka acak:
Perl's Perl_seed () adalah contoh cara menghitung seed dalam C for srand(). Ini mencampur bit dari waktu saat ini, ID proses, dan beberapa petunjuk, jika tidak bisa membaca /dev/urandom.
Terima kasih atas jawaban yang diperluas ini. Perhatikan bahwa dari 24 jawaban saat ini untuk pertanyaan ini, Anda adalah satu-satunya yang memiliki interpretasi ekstra untuk menangani float/ double, jadi saya telah mengklarifikasi pertanyaan untuk tetap berpegang pada intangka untuk menghindari membuatnya terlalu luas. Ada pertanyaan C lain yang berhubungan secara khusus dengan float/ doublenilai acak, jadi Anda mungkin ingin memposting ulang bagian kedua dari jawaban Anda untuk pertanyaan seperti stackoverflow.com/questions/13408990/…
Cœur
11
Jika sistem Anda mendukung arc4randomkeluarga fungsi, saya akan merekomendasikan menggunakan randfungsi standar saja .
arc4random mengembalikan bilangan bulat unsigned 32-bit acak.
arc4random_bufmenempatkan konten acak di parameternya buf : void *. Jumlah konten ditentukan oleh bytes : size_tparameter.
arc4random_uniformmengembalikan bilangan bulat 32-bit unsigned acak yang mengikuti aturan:, di 0 <= arc4random_uniform(limit) < limitmana batasnya juga merupakan integer 32-bit yang tidak ditandatangani.
arc4random_stirmembaca data dari /dev/urandomdan meneruskan data arc4random_addrandomke juga mengacak kumpulan angka acak internal itu.
arc4random_addrandomdigunakan oleh arc4random_stiruntuk mengisi kumpulan nomor acak internal itu menurut data yang diteruskan ke sana.
Jika Anda tidak memiliki fungsi-fungsi ini, tetapi Anda berada di Unix, maka Anda dapat menggunakan kode ini:
/* This is C, not C++ */#include<sys/types.h>#include<sys/stat.h>#include<fcntl.h>#include<errno.h>#include<unistd.h>#include<stdlib.h>/* exit */#include<stdio.h>/* printf */int urandom_fd =-2;void urandom_init(){
urandom_fd = open("/dev/urandom", O_RDONLY);if(urandom_fd ==-1){int errsv = urandom_fd;
printf("Error opening [/dev/urandom]: %i\n", errsv);
exit(1);}}unsignedlong urandom(){unsignedlong buf_impl;unsignedlong*buf =&buf_impl;if(urandom_fd ==-2){
urandom_init();}/* Read 4 bytes, or 32 bits into *buf, which points to buf_impl */
read(urandom_fd, buf,sizeof(long));return buf_impl;}
The urandom_initFungsi membuka /dev/urandomperangkat, dan menempatkan file descriptor di urandom_fd.
The urandomFungsi dasarnya adalah sama sebagai panggilan untuk rand, kecuali lebih aman, dan mengembalikan long(mudah berubah).
Namun, /dev/urandombisa sedikit lambat, sehingga Anda disarankan menggunakannya sebagai seed untuk generator angka acak yang berbeda.
Jika sistem Anda tidak memiliki /dev/urandom, tapi tidak memiliki /dev/randomatau file yang sama, maka Anda hanya bisa mengubah jalan dilewatkan ke opendalam urandom_init. Panggilan dan API yang digunakan dalam urandom_initdan urandom(saya percaya) POSIX-compliant, dan dengan demikian, harus bekerja pada sebagian besar, jika tidak semua sistem yang sesuai dengan POSIX.
Catatan: Pembacaan dari /dev/urandomTIDAK akan memblokir jika ada cukup entropi yang tersedia, sehingga nilai yang dihasilkan dalam keadaan seperti itu mungkin tidak aman secara kriptografis. Jika Anda khawatir tentang itu, maka gunakan /dev/random, yang akan selalu memblokir jika ada cukup entropi.
Jika Anda berada di sistem lain (yaitu Windows), maka gunakan randatau API non-portabel yang bergantung pada platform khusus Windows internal.
Wrapper fungsi untuk urandom, randatau arc4randompanggilan:
STL tidak ada untuk C. Anda harus menelepon rand, atau lebih baik lagi random,. Ini dideklarasikan di header perpustakaan standar stdlib.h. randadalah POSIX, randomadalah fungsi spesifikasi BSD.
Perbedaan antara randdan randomadalah yang randommengembalikan angka acak 32-bit yang lebih dapat digunakan, dan randbiasanya mengembalikan angka 16-bit. Halaman manual BSD menunjukkan bahwa bit yang lebih rendah randbersifat siklik dan dapat diprediksi, sehingga randberpotensi tidak berguna untuk jumlah kecil.
@ Neil - karena semua jawaban sejauh ini menyebutkan STL, saya curiga bahwa pertanyaan itu diedit cepat untuk menghapus referensi yang tidak perlu.
Michael Burr
rand () tidak berguna untuk jumlah kecil - Anda dapat menggeser bitnya keluar dan hanya menggunakan bit tinggi lebih acak jika Anda benar-benar perlu.
Chris Lutz
@ Chris, Anda bisa jika ukuran nomor acak diketahui, tetapi jika ukuran yang diperlukan dari nomor acak berubah selama runtime (seperti mengocok array dinamis dll) akan sulit untuk mengatasi peringatan semacam itu.
dreamlax
Saya tidak dapat menemukan fungsi acak apa pun di sini :-(
kasia.b
@ kasia.b di tautan itu, ada extern int rand(void);dan extern void srand(unsigned int);.
RastaJedi
7
Lihatlah ISAAC (Indirection, Shift, Accumulate, Add, and Count). Didistribusikan secara seragam dan memiliki panjang siklus rata-rata 2 ^ 8295.
Anda ingin menggunakan rand(). Catatan ( SANGAT PENTING ): pastikan untuk mengatur seed untuk fungsi rand. Jika tidak, angka acak Anda tidak benar-benar acak . Ini sangat, sangat, sangat penting. Untungnya, Anda biasanya dapat menggunakan beberapa kombinasi pengingat waktu sistem dan tanggal untuk mendapatkan seed yang bagus.
Dua poin a) angka acak Anda tidak acak, tidak peduli bagaimana Anda menyemai generator. Dan b) sangat mudah untuk memiliki urutan pseudo-acak selalu sama dalam banyak keadaan - untuk pengujian, misalnya.
16
jika SANGAT PENTING bahwa nomor Anda benar-benar acak, Anda tidak boleh menggunakan fungsi rand ().
tylerl
1
Nilai-nilai dari rand sama sekali tidak "benar-benar" acak tidak peduli apakah Anda mengatur seed atau tidak. Diberikan benih yang dikenal urutannya dapat diprediksi. Pembuatan nomor acak "Sungguh" itu sulit. Tidak ada entropi yang terlibat dengan rand.
dreamlax
2
Tentu saja mereka akan - generator diunggulkan untuk Anda oleh perpustakaan (mungkin ke nol, tapi itu benih yang valid).
4
Ah, tetapi algoritma yang dikenal / dikenal benih sangat penting untuk debugging setiap program yang menggunakan angka acak. Bukan tidak biasa untuk mencatat benih yang digunakan bersamaan dengan simulasi sehingga dapat diciptakan kembali untuk analisis yang lebih rinci. Sama sekali tidak memanggil srand () sama dengan memanggil srand (1).
RBerteig
4
FWIW, jawabannya adalah ya, ada stdlib.hfungsi yang disebut rand; fungsi ini disetel terutama untuk kecepatan dan distribusi, bukan untuk ketidakpastian. Hampir semua fungsi acak bawaan untuk berbagai bahasa dan kerangka kerja menggunakan fungsi ini secara default. Ada juga generator nomor acak "kriptografi" yang jauh lebih mudah diprediksi, tetapi berjalan jauh lebih lambat. Ini harus digunakan dalam segala jenis aplikasi yang berhubungan dengan keamanan.
menambahkan srand (rand ()) tidak meningkatkan keacakan urutan jika program ini dijalankan beberapa kali dalam 1 detik. waktu (NULL) masih akan mengembalikan nilai yang sama untuk masing-masing, rand pertama () akan mengembalikan panjang yang sama, dan panggilan kedua ke srand () akan dengan nilai yang sama, sehingga masih memiliki urutan acak yang sama. Penggunaan alamat argc dapat membantu, hanya jika dijamin bahwa alamat ini akan berbeda pada setiap pelaksanaan program, yang tidak selalu benar.
theferrit32
3
STL adalah C ++, bukan C, jadi saya tidak tahu apa yang Anda inginkan. Namun, jika Anda menginginkan C, ada rand()dan srand()fungsinya:
int rand(void);void srand(unsigned seed);
Keduanya adalah bagian dari ANSI C. Ada juga random()fungsinya:
long random(void);
Tapi sejauh yang saya tahu, random()itu bukan standar ANSI C. Perpustakaan pihak ketiga mungkin bukan ide yang buruk, tetapi semuanya tergantung pada seberapa acak angka yang benar-benar Anda butuhkan untuk menghasilkan.
Anda juga dapat memperoleh nomor acak dari layanan online seperti Bounty random.org jika Anda menyertakan cara portabel dan efisien untuk melakukan ini dalam C.
MD XF
2
#include<stdio.h>#include<stdlib.h>void main(){int visited[100];int randValue, a, b, vindex =0;
randValue =(rand()%100)+1;while(vindex <100){for(b =0; b < vindex; b++){if(visited[b]== randValue){
randValue =(rand()%100)+1;
b =0;}}
visited[vindex++]= randValue;}for(a =0; a <100; a++)
printf("%d ", visited[a]);}
Pada saat saya membuat komentar itu, saya tidak memiliki izin edit universal, dan umumnya perubahan kode yang mengubah jawaban yang sebenarnya akan ditolak. Jika Anda tidak peduli untuk memperbaiki jawaban Anda, saya bisa.
b4hand
Jika niat Anda adalah untuk menghasilkan permutasi acak dari nilai-nilai unik, kode ini masih memiliki bug. Ini menghasilkan nilai 84 dua kali dan tidak menghasilkan nilai 48. Selain itu, tidak menghasilkan generator nomor acak sehingga urutannya sama pada setiap eksekusi.
tangani
1
variabel a dan b didefinisikan dalam kode ini .. Ini bebas kesalahan .. tidak ada sintaks dan kesalahan logis juga.
Muhammad Sadiq
Salah. Saya sudah mengkonfirmasi output seperti yang saya sebutkan.
b4hand
1
#include<stdio.h>#include<dos.h>int random(int range);int main(void){
printf("%d", random(10));return0;}int random(int range){struct time t;int r;
gettime(&t);
r = t.ti_sec % range;return r;}
Pada CPU x86_64 modern Anda dapat menggunakan generator nomor acak perangkat keras via _rdrand64_step()
Kode contoh:
#include<immintrin.h>uint64_t randVal;if(!_rdrand64_step(&randVal)){// Report an error here: random number generation has failed!}// If no error occured, randVal contains a random 64-bit number
#include<stdio.h>#include<stdlib.h>#include<time.h>//generate number in range [min,max)int random(int min,int max){int number = min + rand()%(max - min);return number;}//Driver codeint main(){
srand(time(NULL));for(int i =1; i <=10; i++){
printf("%d\t", random(10,100));}return0;}
Mendengar penjelasan yang baik tentang mengapa menggunakan rand()untuk menghasilkan angka acak yang terdistribusi secara seragam dalam rentang yang diberikan adalah ide yang buruk, saya memutuskan untuk melihat bagaimana kemiringan output sebenarnya. Kasus tes saya adalah melempar dadu dengan adil. Ini kode C:
#include<stdio.h>#include<stdlib.h>#include<time.h>int main(int argc,char*argv[]){int i;int dice[6];for(i =0; i <6; i++)
dice[i]=0;
srand(time(NULL));constint TOTAL =10000000;for(i =0; i < TOTAL; i++)
dice[(rand()%6)]+=1;double pers =0.0, tpers =0.0;for(i =0; i <6; i++){
pers =(dice[i]*100.0)/ TOTAL;
printf("\t%1d %5.2f%%\n", dice[i], pers);
tpers += pers;}
printf("\ttotal: %6.2f%%\n", tpers);}
rand () dapat gagal dalam tes keacakan lainnya, seperti tes diehard . rand () berbeda dari platform ke platform; nilai rand () dari GNU / Linux mungkin lebih baik daripada nilai dari BSD atau Windows.
George Koehler
Ini bukan cara yang valid untuk menguji keacakan.
Veedrac
Tergantung pada tujuan dan model ancaman / risiko. Untuk RNG yang kuat secara kriptografis - tentu saja, gunakan RDRAND (atau RDSEED). Untuk pelempar dadu sederhana (bukan tingkat kasino) IMHO di atas sudah cukup. Kata kuncinya adalah " cukup baik ".
Mouse
0
Saya memiliki masalah serius dengan pseudo random generator angka dalam aplikasi saya baru-baru ini: Saya berulang kali memanggil program C saya melalui skrip pyhton dan saya gunakan sebagai seed kode berikut:
srand(time(NULL))
Namun, sejak:
rand akan menghasilkan urutan acak semu yang sama memberikan benih yang sama dalam srand (lihat man srand );
Seperti yang telah dinyatakan, fungsi waktu berubah hanya detik dari detik: jika aplikasi Anda dijalankan beberapa kali dalam detik yang sama, timeakan mengembalikan nilai yang sama setiap kali.
Program saya menghasilkan urutan angka yang sama. Anda dapat melakukan 3 hal untuk menyelesaikan masalah ini:
mencampur output waktu dengan beberapa informasi lain yang berubah saat berjalan (dalam aplikasi saya, nama output):
Opsi 3 memastikan Anda (sejauh yang saya tahu) keacakan benih terbaik, tetapi mungkin membuat perbedaan hanya pada aplikasi yang sangat cepat. Menurut saya opsi 2 adalah taruhan yang aman.
Bahkan dengan heuristik ini, jangan bergantung pada rand () untuk data kriptografi.
domenukk
rand()tidak boleh digunakan untuk data kriptografi, saya setuju. Setidaknya bagi saya, aplikasi saya tidak melibatkan data kriptografi, jadi bagi saya itu ok metode yang diberikan.
Koldar
0
Terlepas dari semua saran orang di rand()sini, Anda tidak ingin menggunakan rand()kecuali Anda harus! Angka acak yang rand()menghasilkan seringkali sangat buruk. Mengutip dari halaman manual Linux:
Versi rand()dan srand()di Linux C Library menggunakan generator angka acak yang sama dengan random(3)dan srandom(3), sehingga bit urutan rendah harus acak seperti bit urutan yang lebih tinggi. Namun, pada implementasi rand () lama, dan pada implementasi saat ini pada sistem yang berbeda, bit orde rendah jauh lebih sedikit acak daripada bit orde tinggi . Jangan gunakan fungsi ini dalam aplikasi yang dimaksudkan untuk portabel ketika keacakan yang baik diperlukan. ( Gunakan random(3)saja. )
Mengenai portabilitas, random()juga ditentukan oleh standar POSIX untuk beberapa waktu sekarang. rand()lebih tua, sudah muncul di spec POSIX.1 pertama (IEEE Std 1003.1-1988), sedangkan yang random()pertama muncul di POSIX.1-2001 (IEEE Std 1003.1-2001), namun standar POSIX saat ini sudah POSIX.1-2008 (IEEE Std 1003.1-2008), yang menerima pembaruan setahun yang lalu (IEEE Std 1003.1-2008, Edisi 2016). Jadi saya akan mempertimbangkanrandom() sangat portabel.
POSIX.1-2001 juga memperkenalkan lrand48()dan mrand48()fungsinya, lihat di sini :
Rangkaian fungsi ini akan menghasilkan angka pseudo-acak menggunakan algoritma linear kongruensial dan aritmatika integer 48-bit.
Dan sumber acak semu yang cukup bagus adalah arc4random() fungsi yang tersedia di banyak sistem. Bukan bagian dari standar resmi apa pun, muncul di BSD sekitar tahun 1997 tetapi Anda dapat menemukannya di sistem seperti Linux dan macOS / iOS.
@ BjörnLindqvist Windows juga bukan sistem POSIX; itu cukup banyak satu-satunya sistem di pasar yang tidak mendukung setidaknya API POSIX dasar (yang bahkan mengunci sistem seperti iOS tidak mendukung). Windows hanya mendukung rand()karena juga diperlukan oleh standar C. Untuk hal lain, Anda memerlukan solusi khusus untuk Windows saja, seperti biasa. #ifdef _WIN32adalah ungkapan yang paling sering Anda lihat dalam kode lintas platform yang ingin mendukung Windows dan biasanya ada satu solusi yang bekerja dengan semua sistem dan satu yang diperlukan untuk Windows saja.
Mecki
0
Untuk aplikasi Linux C:
Ini adalah kode ulang saya dari jawaban di atas yang mengikuti praktik kode C saya dan mengembalikan buffer acak dalam berbagai ukuran (dengan kode pengembalian yang tepat, dll.). Pastikan untuk menelepon urandom_open()sekali di awal program Anda.
int gUrandomFd =-1;int urandom_open(void){if(gUrandomFd ==-1){
gUrandomFd = open("/dev/urandom", O_RDONLY);}if(gUrandomFd ==-1){
fprintf(stderr,"Error opening /dev/urandom: errno [%d], strerrer [%s]\n",
errno, strerror(errno));return-1;}else{return0;}}void urandom_close(void){
close(gUrandomFd);
gUrandomFd =-1;}//// This link essentially validates the merits of /dev/urandom:// http://sockpuppet.org/blog/2014/02/25/safely-generate-random-numbers///int getRandomBuffer(uint8_t*buf,int size){int ret =0;// Return valueif(gUrandomFd ==-1){
fprintf(stderr,"Urandom (/dev/urandom) file not open\n");return-1;}
ret = read(gUrandomFd, buf, size);if(ret != size){
fprintf(stderr,"Only read [%d] bytes, expected [%d]\n",
ret, size);return-1;}else{return0;}}
Solusi minimalis saya harus bekerja untuk angka acak dalam jangkauan [min, max). Gunakan srand(time(NULL))sebelum memanggil fungsi.
int range_rand(int min_num,int max_num){if(min_num >= max_num){
fprintf(stderr,"min_num is greater or equal than max_num!\n");}return min_num +(rand()%(max_num - min_num));}
Coba ini, saya menggabungkannya dari beberapa konsep yang telah dirujuk di atas:
/*
Uses the srand() function to seed the random number generator based on time value,
then returns an integer in the range 1 to max. Call this with random(n) where n is an integer, and you get an integer as a return value.
*/int random(int max){
srand((unsigned) time(NULL));return(rand()% max)+1;}
Kode ini tidak bagus. Menelepon srand()setiap kali Anda ingin menelepon rand()adalah ide yang buruk. Karena time()biasanya mengembalikan nilai dalam hitungan detik yang memanggil fungsi ini dengan cepat akan mengembalikan nilai "acak" yang sama.
Blastfurnace
3
Fungsi ini akan menjadi bingung dengan random()fungsi Unix .
srand
: mengapa menyebutnya hanya sekali .Jawaban:
Sunting : Di Linux, Anda mungkin lebih suka menggunakan acak dan acak .
sumber
time()
hanya berubah sekali per detik. Jika Anda memotong daritime()
, untuk setiap panggilanrand()
, maka Anda akan mendapatkan nilai yang sama untuk setiap panggilan selama satu detik. Tetapi alasan yang lebih besar adalah bahwa propertirand()
dan fungsi seperti itu dikenal terbaik untuk use case di mana mereka diunggulkan tepat sekali per run, dan tidak pada setiap panggilan tunggal. Bergantung pada "keacakan" dengan properti yang belum diuji atau tidak terbukti menyebabkan masalah.rand()
biasanya adalah) penyemaian dengan cararand()
terbaik tidak akan berpengaruh sama sekali, dan paling buruk akan merusak kualitas generator yang diketahui. Ini adalah subjek yang mendalam. Mulailah dengan membaca Knuth Vol 2 Bab 3 pada angka acak sebagai pengantar terbaik untuk matematika dan perangkap.srand((unsigned int)time(NULL));
The
rand()
fungsi dalam<stdlib.h>
pengembalian integer pseudo-acak antara 0 danRAND_MAX
. Anda bisa menggunakansrand(unsigned int seed)
untuk mengatur seed.Ini adalah praktik umum untuk menggunakan
%
operator bersamaanrand()
untuk mendapatkan rentang yang berbeda (meskipun perlu diingat bahwa ini agak menghilangkan keseragaman). Sebagai contoh:Jika Anda benar-benar peduli tentang keseragaman, Anda dapat melakukan sesuatu seperti ini:
sumber
%
Adalah operator modulus. Ini memberi Anda sisa dari divisi integer, jadix % n
akan selalu memberi Anda nomor di antara0
dann - 1
(selamax
dann
keduanya positif). Jika Anda masih merasa itu membingungkan, cobalah menulis sebuah program yang memilikii
hitungan dari 0 hingga 100, dan cetaki % n
untuk beberapan
pilihan Anda yang lebih kecil dari 100.Jika Anda memerlukan karakter atau integer acak yang aman:
Sebagaimana dibahas dalam cara menghasilkan angka acak dengan aman dalam berbagai bahasa pemrograman , Anda harus melakukan salah satu dari yang berikut:
randombytes
API/dev/urandom
, bukan/dev/random
. Bukan OpenSSL (atau PRNGs userspace lainnya).Sebagai contoh:
randombytes_uniform()
aman secara kriptografis dan tidak bias.sumber
sodium_init()
di beberapa titik. Jangan khawatir tentang RNG, karena menggunakan kernel.sodium_init()
walaupun itu belum tentu menjadi bagian dari contoh saya karena ini merupakan detail penting.Mari kita pergi melalui ini. Pertama-tama kita menggunakan fungsi srand () untuk seed randomizer. Pada dasarnya, komputer dapat menghasilkan angka acak berdasarkan nomor yang diumpankan ke srand (). Jika Anda memberikan nilai seed yang sama, maka angka acak yang sama akan dihasilkan setiap waktu.
Oleh karena itu, kita harus menyemai randomizer dengan nilai yang selalu berubah. Kami melakukan ini dengan memberinya nilai waktu saat ini dengan fungsi time ().
Sekarang, ketika kita memanggil rand (), nomor acak baru akan dihasilkan setiap saat.
sumber
else{ low_num=max_num; hi_num=min_num+1;
2) gagal saathi_num - low_num > INT_MAX
. 3) Menghilangkan nilai dalam situasi yang jarang terjadiINT_MAX > hi_num - low_num > RAND_MAX
.hi_num = max_num + 1;
tidak memiliki perlindungan terhadap luapan.Jika Anda membutuhkan nomor acak semu yang lebih baik daripada yang
stdlib
disediakan, periksa Mersenne Twister . Lebih cepat juga. Implementasi sampel berlimpah, misalnya di sini .sumber
Fungsi standar C adalah
rand()
. Cukup bagus untuk menangani kartu untuk solitaire, tapi itu mengerikan. Banyak implementasirand()
siklus melalui daftar angka pendek, dan bit rendah memiliki siklus yang lebih pendek. Cara beberapa program menyebutnyarand()
mengerikan, dan menghitung benih yang baik untuk dilewatkansrand()
adalah sulit.Cara terbaik untuk menghasilkan angka acak dalam C adalah dengan menggunakan perpustakaan pihak ketiga seperti OpenSSL. Sebagai contoh,
Mengapa begitu banyak kode? Bahasa lain seperti Java dan Ruby memiliki fungsi untuk bilangan bulat acak atau float. OpenSSL hanya memberikan byte acak, jadi saya mencoba untuk meniru bagaimana Java atau Ruby akan mengubahnya menjadi bilangan bulat atau mengapung.
Untuk bilangan bulat, kami ingin menghindari bias modulo . Misalkan kita mendapatkan beberapa bilangan bulat 4 digit acak
rand() % 10000
, tetapirand()
hanya dapat mengembalikan 0 hingga 32767 (seperti halnya di Microsoft Windows). Setiap angka dari 0 hingga 2767 akan muncul lebih sering daripada setiap angka dari 2768 hingga 9999. Untuk menghapus bias, kita dapat mencoba lagirand()
sementara nilainya di bawah 2768, karena nilai-nilai 30000 dari 2768 hingga 32767 memetakan secara seragam ke nilai 10000 dari 0 hingga 9999.Untuk mengapung, kami ingin 53 bit acak, karena
double
memegang 53 bit presisi (dengan asumsi itu adalah ganda IEEE). Jika kita menggunakan lebih dari 53 bit, kita mendapatkan bias pembulatan. Beberapa programmer menulis kode sepertirand() / (double)RAND_MAX
, tetapirand()
mungkin mengembalikan hanya 31 bit, atau hanya 15 bit di Windows.RAND_bytes()
Benih OpenSSL sendiri, mungkin dengan membaca/dev/urandom
di Linux. Jika kita memerlukan banyak angka acak, akan terlalu lambat untuk membacanya/dev/urandom
, karena mereka harus disalin dari kernel. Lebih cepat untuk memungkinkan OpenSSL menghasilkan lebih banyak angka acak dari sebuah seed.Lebih lanjut tentang angka acak:
srand()
. Ini mencampur bit dari waktu saat ini, ID proses, dan beberapa petunjuk, jika tidak bisa membaca/dev/urandom
.sumber
float
/double
, jadi saya telah mengklarifikasi pertanyaan untuk tetap berpegang padaint
angka untuk menghindari membuatnya terlalu luas. Ada pertanyaan C lain yang berhubungan secara khusus denganfloat
/double
nilai acak, jadi Anda mungkin ingin memposting ulang bagian kedua dari jawaban Anda untuk pertanyaan seperti stackoverflow.com/questions/13408990/…Jika sistem Anda mendukung
arc4random
keluarga fungsi, saya akan merekomendasikan menggunakanrand
fungsi standar saja .The
arc4random
keluarga meliputi:arc4random
mengembalikan bilangan bulat unsigned 32-bit acak.arc4random_buf
menempatkan konten acak di parameternyabuf : void *
. Jumlah konten ditentukan olehbytes : size_t
parameter.arc4random_uniform
mengembalikan bilangan bulat 32-bit unsigned acak yang mengikuti aturan:, di0 <= arc4random_uniform(limit) < limit
mana batasnya juga merupakan integer 32-bit yang tidak ditandatangani.arc4random_stir
membaca data dari/dev/urandom
dan meneruskan dataarc4random_addrandom
ke juga mengacak kumpulan angka acak internal itu.arc4random_addrandom
digunakan oleharc4random_stir
untuk mengisi kumpulan nomor acak internal itu menurut data yang diteruskan ke sana.Jika Anda tidak memiliki fungsi-fungsi ini, tetapi Anda berada di Unix, maka Anda dapat menggunakan kode ini:
The
urandom_init
Fungsi membuka/dev/urandom
perangkat, dan menempatkan file descriptor diurandom_fd
.The
urandom
Fungsi dasarnya adalah sama sebagai panggilan untukrand
, kecuali lebih aman, dan mengembalikanlong
(mudah berubah).Namun,
/dev/urandom
bisa sedikit lambat, sehingga Anda disarankan menggunakannya sebagai seed untuk generator angka acak yang berbeda.Jika sistem Anda tidak memiliki
/dev/urandom
, tapi tidak memiliki/dev/random
atau file yang sama, maka Anda hanya bisa mengubah jalan dilewatkan keopen
dalamurandom_init
. Panggilan dan API yang digunakan dalamurandom_init
danurandom
(saya percaya) POSIX-compliant, dan dengan demikian, harus bekerja pada sebagian besar, jika tidak semua sistem yang sesuai dengan POSIX.Catatan: Pembacaan dari
/dev/urandom
TIDAK akan memblokir jika ada cukup entropi yang tersedia, sehingga nilai yang dihasilkan dalam keadaan seperti itu mungkin tidak aman secara kriptografis. Jika Anda khawatir tentang itu, maka gunakan/dev/random
, yang akan selalu memblokir jika ada cukup entropi.Jika Anda berada di sistem lain (yaitu Windows), maka gunakan
rand
atau API non-portabel yang bergantung pada platform khusus Windows internal.Wrapper fungsi untuk
urandom
,rand
atauarc4random
panggilan:sumber
STL tidak ada untuk C. Anda harus menelepon
rand
, atau lebih baik lagirandom
,. Ini dideklarasikan di header perpustakaan standarstdlib.h
.rand
adalah POSIX,random
adalah fungsi spesifikasi BSD.Perbedaan antara
rand
danrandom
adalah yangrandom
mengembalikan angka acak 32-bit yang lebih dapat digunakan, danrand
biasanya mengembalikan angka 16-bit. Halaman manual BSD menunjukkan bahwa bit yang lebih rendahrand
bersifat siklik dan dapat diprediksi, sehinggarand
berpotensi tidak berguna untuk jumlah kecil.sumber
extern int rand(void);
danextern void srand(unsigned int);
.Lihatlah ISAAC (Indirection, Shift, Accumulate, Add, and Count). Didistribusikan secara seragam dan memiliki panjang siklus rata-rata 2 ^ 8295.
sumber
Ini adalah cara yang baik untuk mendapatkan angka acak antara dua angka pilihan Anda.
Keluaran pertama kali: 39
Keluaran untuk kedua kalinya: 61
Keluaran yang ketiga kalinya: 65
Anda dapat mengubah nilai setelah
randnum
ke nomor apa pun yang Anda pilih, dan itu akan menghasilkan angka acak untuk Anda di antara dua angka itu.sumber
Anda ingin menggunakan
rand()
. Catatan ( SANGAT PENTING ): pastikan untuk mengatur seed untuk fungsi rand. Jika tidak, angka acak Anda tidak benar-benar acak . Ini sangat, sangat, sangat penting. Untungnya, Anda biasanya dapat menggunakan beberapa kombinasi pengingat waktu sistem dan tanggal untuk mendapatkan seed yang bagus.sumber
FWIW, jawabannya adalah ya, ada
stdlib.h
fungsi yang disebutrand
; fungsi ini disetel terutama untuk kecepatan dan distribusi, bukan untuk ketidakpastian. Hampir semua fungsi acak bawaan untuk berbagai bahasa dan kerangka kerja menggunakan fungsi ini secara default. Ada juga generator nomor acak "kriptografi" yang jauh lebih mudah diprediksi, tetapi berjalan jauh lebih lambat. Ini harus digunakan dalam segala jenis aplikasi yang berhubungan dengan keamanan.sumber
Mudah-mudahan ini sedikit lebih acak daripada hanya menggunakan
srand(time(NULL))
.sumber
STL adalah C ++, bukan C, jadi saya tidak tahu apa yang Anda inginkan. Namun, jika Anda menginginkan C, ada
rand()
dansrand()
fungsinya:Keduanya adalah bagian dari ANSI C. Ada juga
random()
fungsinya:Tapi sejauh yang saya tahu,
random()
itu bukan standar ANSI C. Perpustakaan pihak ketiga mungkin bukan ide yang buruk, tetapi semuanya tergantung pada seberapa acak angka yang benar-benar Anda butuhkan untuk menghasilkan.sumber
Program C untuk menghasilkan angka acak antara 9 dan 50
Secara umum kita dapat menghasilkan angka acak antara lowerLimit dan upperLimit-1
yaitu lowerLimit termasuk atau katakan r ∈ [lowerLimit, upperLimit)
sumber
rand()
adalah cara paling mudah untuk menghasilkan angka acak.Anda juga dapat memperoleh nomor acak dari layanan online seperti random.org.
sumber
sumber
sumber
Pada CPU x86_64 modern Anda dapat menggunakan generator nomor acak perangkat keras via
_rdrand64_step()
Kode contoh:
sumber
sumber
Mendengar penjelasan yang baik tentang mengapa menggunakan
rand()
untuk menghasilkan angka acak yang terdistribusi secara seragam dalam rentang yang diberikan adalah ide yang buruk, saya memutuskan untuk melihat bagaimana kemiringan output sebenarnya. Kasus tes saya adalah melempar dadu dengan adil. Ini kode C:dan inilah hasilnya:
Saya tidak tahu seberapa seragam Anda perlu nomor acak Anda, tetapi di atas tampak cukup seragam untuk sebagian besar kebutuhan.
Sunting: itu akan menjadi ide yang baik untuk menginisialisasi PRNG dengan sesuatu yang lebih baik daripada
time(NULL)
.sumber
Saya memiliki masalah serius dengan pseudo random generator angka dalam aplikasi saya baru-baru ini: Saya berulang kali memanggil program C saya melalui skrip pyhton dan saya gunakan sebagai seed kode berikut:
Namun, sejak:
man srand
);time
akan mengembalikan nilai yang sama setiap kali.Program saya menghasilkan urutan angka yang sama. Anda dapat melakukan 3 hal untuk menyelesaikan masalah ini:
mencampur output waktu dengan beberapa informasi lain yang berubah saat berjalan (dalam aplikasi saya, nama output):
Saya menggunakan djb2 sebagai fungsi hash saya.
Tambah resolusi waktu. Di platform saya,
clock_gettime
tersedia, jadi saya menggunakannya:Gunakan kedua metode bersama-sama:
Opsi 3 memastikan Anda (sejauh yang saya tahu) keacakan benih terbaik, tetapi mungkin membuat perbedaan hanya pada aplikasi yang sangat cepat. Menurut saya opsi 2 adalah taruhan yang aman.
sumber
rand()
tidak boleh digunakan untuk data kriptografi, saya setuju. Setidaknya bagi saya, aplikasi saya tidak melibatkan data kriptografi, jadi bagi saya itu ok metode yang diberikan.Terlepas dari semua saran orang di
rand()
sini, Anda tidak ingin menggunakanrand()
kecuali Anda harus! Angka acak yangrand()
menghasilkan seringkali sangat buruk. Mengutip dari halaman manual Linux:Mengenai portabilitas,
random()
juga ditentukan oleh standar POSIX untuk beberapa waktu sekarang.rand()
lebih tua, sudah muncul di spec POSIX.1 pertama (IEEE Std 1003.1-1988), sedangkan yangrandom()
pertama muncul di POSIX.1-2001 (IEEE Std 1003.1-2001), namun standar POSIX saat ini sudah POSIX.1-2008 (IEEE Std 1003.1-2008), yang menerima pembaruan setahun yang lalu (IEEE Std 1003.1-2008, Edisi 2016). Jadi saya akan mempertimbangkanrandom()
sangat portabel.POSIX.1-2001 juga memperkenalkan
lrand48()
danmrand48()
fungsinya, lihat di sini :Dan sumber acak semu yang cukup bagus adalah
arc4random()
fungsi yang tersedia di banyak sistem. Bukan bagian dari standar resmi apa pun, muncul di BSD sekitar tahun 1997 tetapi Anda dapat menemukannya di sistem seperti Linux dan macOS / iOS.sumber
random()
tidak ada di Windows.rand()
karena juga diperlukan oleh standar C. Untuk hal lain, Anda memerlukan solusi khusus untuk Windows saja, seperti biasa.#ifdef _WIN32
adalah ungkapan yang paling sering Anda lihat dalam kode lintas platform yang ingin mendukung Windows dan biasanya ada satu solusi yang bekerja dengan semua sistem dan satu yang diperlukan untuk Windows saja.Untuk aplikasi Linux C:
Ini adalah kode ulang saya dari jawaban di atas yang mengikuti praktik kode C saya dan mengembalikan buffer acak dalam berbagai ukuran (dengan kode pengembalian yang tepat, dll.). Pastikan untuk menelepon
urandom_open()
sekali di awal program Anda.sumber
Solusi minimalis saya harus bekerja untuk angka acak dalam jangkauan
[min, max)
. Gunakansrand(time(NULL))
sebelum memanggil fungsi.sumber
Coba ini, saya menggabungkannya dari beberapa konsep yang telah dirujuk di atas:
sumber
srand()
setiap kali Anda ingin meneleponrand()
adalah ide yang buruk. Karenatime()
biasanya mengembalikan nilai dalam hitungan detik yang memanggil fungsi ini dengan cepat akan mengembalikan nilai "acak" yang sama.random()
fungsi Unix .