Saya mencoba membuat permainan dengan dadu, dan saya perlu memiliki angka acak di dalamnya (untuk mensimulasikan sisi-sisi dadu. Saya tahu bagaimana membuatnya antara 1 dan 6). Menggunakan
#include <cstdlib>
#include <ctime>
#include <iostream>
using namespace std;
int main()
{
srand((unsigned)time(0));
int i;
i = (rand()%6)+1;
cout << i << "\n";
}
tidak bekerja dengan baik, karena ketika saya menjalankan program beberapa kali, inilah output yang saya dapatkan:
6
1
1
1
1
1
2
2
2
2
5
2
Jadi saya ingin perintah yang akan menghasilkan angka acak yang berbeda setiap kali, bukan yang sama 5 kali berturut-turut. Apakah ada perintah yang akan melakukan ini?
Jawaban:
Masalah paling mendasar dari aplikasi pengujian Anda adalah bahwa Anda menelepon
srand
sekali dan kemudian memanggilrand
satu kali dan keluar.Inti dari
srand
fungsi adalah untuk menginisialisasi urutan bilangan pseudo-acak dengan seed acak.Ini berarti bahwa jika Anda lulus nilai yang sama untuk
srand
dua aplikasi yang berbeda (dengan samasrand
/rand
pelaksanaan) maka Anda akan mendapatkan persis urutan yang sama darirand()
nilai-nilai membaca setelah itu di kedua aplikasi.Namun dalam contoh aplikasi Anda urutan pseudo-acak hanya terdiri dari satu elemen - elemen pertama dari urutan pseudo-acak yang dihasilkan dari seed sama dengan waktu
second
presisi saat ini. Apa yang Anda harapkan dari output?Tentunya ketika Anda menjalankan aplikasi pada detik yang sama - Anda menggunakan nilai seed yang sama - dengan demikian hasil Anda sama saja (seperti Martin York sudah disebutkan dalam komentar untuk pertanyaan).
Sebenarnya Anda harus menelepon
srand(seed)
satu kali dan kemudian meneleponrand()
berkali-kali dan menganalisis urutan itu - itu akan terlihat acak.EDIT:
Oh, aku mengerti. Rupanya deskripsi verbal tidak cukup (mungkin hambatan bahasa atau sesuatu ... :)).
BAIK. Contoh kode C kuno berdasarkan pada
srand()/rand()/time()
fungsi yang sama yang digunakan dalam pertanyaan:^^^ ITU berurutan dari menjalankan tunggal dari program ini seharusnya terlihat acak.
EDIT2:
Ketika menggunakan pustaka standar C atau C ++, penting untuk dipahami bahwa sampai sekarang tidak ada fungsi standar tunggal atau kelas yang benar-benar menghasilkan data acak (dijamin oleh standar). Satu-satunya alat standar yang mendekati masalah ini adalah std :: random_device yang sayangnya masih tidak memberikan jaminan keacakan yang sebenarnya.
Tergantung pada sifat aplikasi Anda harus memutuskan terlebih dahulu apakah Anda benar-benar membutuhkan data yang benar-benar acak (tidak dapat diprediksi). Kasus penting ketika Anda paling pasti membutuhkan keacakan benar adalah keamanan informasi - misalnya menghasilkan kunci simetris, kunci pribadi asimetris, nilai garam, token keamanan, dll.
Namun angka acak tingkat keamanan adalah industri terpisah yang bernilai artikel terpisah.
Dalam kebanyakan kasus Pseudo-Random Number Generator sudah cukup - misalnya untuk simulasi ilmiah atau permainan. Dalam beberapa kasus, urutan pseudo-acak yang didefinisikan secara konsisten bahkan diperlukan - misalnya dalam game Anda dapat memilih untuk menghasilkan peta yang sama persis dalam runtime untuk menghindari penyimpanan banyak data.
Pertanyaan asli dan pengulangan banyak pertanyaan yang identik / serupa (dan bahkan banyak "jawaban" yang salah kepada mereka) menunjukkan bahwa pertama dan terutama penting untuk membedakan angka acak dari angka pseudo-acak DAN untuk memahami apa urutan nomor pseudo-acak dalam tempat pertama DAN untuk menyadari bahwa generator nomor pseudo-acak TIDAK digunakan dengan cara yang sama Anda bisa menggunakan generator nomor acak benar.
^^^ ITU semacam ekspektasi intuitif SANGAT SALAH dan berbahaya dalam semua kasus yang melibatkan Pseudo-Random Number Generator - meskipun masuk akal untuk nomor acak yang sebenarnya.
Sementara pengertian "bilangan acak" yang berarti ada - tidak ada yang namanya "bilangan acak-semu". Sebuah Pseudo-Random Number Generator benar-benar menghasilkan pseudo-acak nomor urut .
Ketika para ahli berbicara tentang kualitas PRNG mereka benar-benar berbicara tentang sifat statistik dari urutan yang dihasilkan (dan sub-urutan yang penting). Misalnya jika Anda menggabungkan dua PRNG berkualitas tinggi dengan menggunakan keduanya secara bergantian - Anda dapat menghasilkan urutan hasil yang buruk - meskipun mereka menghasilkan urutan yang baik masing-masing secara terpisah (dua urutan yang baik mungkin hanya berkorelasi satu sama lain dan dengan demikian menggabungkan dengan buruk).
Urutan pseudo-acak sebenarnya selalu deterministik (ditentukan sebelumnya oleh algoritma dan parameter awal) yaitu sebenarnya tidak ada yang acak tentang hal itu.
Secara khusus
rand()
/srand(s)
sepasang fungsi menyediakan urutan nomor pseudo-acak pseudo-acak tunggal per-proses tunggal yang dihasilkan dengan algoritma yang ditentukan-implementasi. Fungsirand()
menghasilkan nilai dalam rentang[0, RAND_MAX]
.Kutipan dari standar C11:
Banyak orang cukup berharap bahwa
rand()
akan menghasilkan urutan semi-independen nomor terdistribusi secara merata dalam kisaran0
untukRAND_MAX
. Yah itu pasti harus (kalau tidak itu tidak berguna) tapi sayangnya tidak hanya standar tidak mengharuskan - bahkan ada penyangkalan eksplisit yang menyatakan "tidak ada jaminan untuk kualitas urutan acak yang dihasilkan" . Dalam beberapa kasus sejarahrand
/srand
implementasi memang kualitasnya sangat buruk. Meskipun dalam implementasi modern kemungkinan besar cukup baik - tetapi kepercayaan itu rusak dan tidak mudah untuk pulih. Selain itu sifatnya yang non-thread-safe membuat penggunaannya yang aman dalam aplikasi multi-thread menjadi sulit dan terbatas (masih mungkin - Anda dapat menggunakannya dari satu utas khusus).Template kelas baru std :: mersenne_twister_engine <> (dan kemudahan mengetiknya -
std::mt19937
/std::mt19937_64
dengan kombinasi parameter template yang baik) menyediakan per-objek generator nomor pseudo-acak didefinisikan dalam standar C ++ 11. Dengan parameter templat yang sama dan parameter inisialisasi yang sama, objek yang berbeda akan menghasilkan urutan output per objek yang persis sama pada komputer apa pun di aplikasi apa pun yang dibangun dengan pustaka standar yang memenuhi standar C ++ 11. Keuntungan dari kelas ini adalah urutan output yang diprediksi berkualitas tinggi dan konsistensi penuh di seluruh implementasi.Juga ada lebih banyak mesin PRNG yang didefinisikan dalam standar C ++ 11 - std :: linear_congruential_engine <> (secara historis digunakan sebagai
srand/rand
algoritma kualitas adil dalam beberapa implementasi perpustakaan standar C) dan std :: subtract_with_carry_engine <> . Mereka juga menghasilkan urutan output per objek yang ditentukan-parameter sepenuhnya ditentukan.Modern C + + 11 contoh pengganti untuk kode C usang di atas:
Versi kode sebelumnya yang menggunakan std :: uniform_int_distribution <>
sumber
rand()
dansrand()
. Bisakah Anda memperbaruinya?rand()
dansrand()
. Bahkan itu hanya menjawab pertanyaan dengan deskripsi yang diberikan. Jelas dari deskripsi (yang menggunakanrand
/srand
) bahwa konsep dasar generasi bilangan pseudo-acak harus dijelaskan - seperti makna urutan pseudo-acak dan keturunannya. Saya mencoba untuk melakukan hal itu dan menggunakan kombinasirand
/ yang paling sederhana dan akrabsrand
. Yang lucu adalah bahwa beberapa jawaban lain - bahkan dengan peringkat sangat besar - menderita kesalahpahaman yang sama dengan penulis pertanyaan.std::rand/std::srand
fitur perpustakaan C ++ lama DAN baru sepertistd::random_device<>
, std :: mersenne_twister_engine <> dan banyak distribusi acak memerlukan beberapa penjelasan.Menggunakan modulo dapat menyebabkan bias ke dalam angka acak, tergantung pada generator angka acak. Lihat pertanyaan ini untuk info lebih lanjut. Tentu saja, sangat mungkin untuk mendapatkan angka berulang dalam urutan acak.
Cobalah beberapa fitur C ++ 11 untuk distribusi yang lebih baik:
Lihat pertanyaan / jawaban ini untuk info lebih lanjut tentang C ++ 11 angka acak. Di atas bukan satu-satunya cara untuk melakukan ini, tetapi satu cara.
sumber
%6
semakin kecil. Mungkin penting jika Anda menulis game dadu untuk digunakan di Las Vegas, tetapi tidak ada konsekuensi dalam hampir semua konteks lainnya.random_device
danmt19937
sudah ada, secara harfiah tidak ada alasan untuk tidak keluar semua dan menggunakan standaruniform_int_distribution
juga.Jika Anda menggunakan boost libs, Anda bisa mendapatkan generator acak dengan cara ini:
Di mana fungsinya
current_time_nanoseconds()
memberikan waktu saat ini dalam nanodetik yang digunakan sebagai benih.Berikut adalah kelas yang lebih umum untuk mendapatkan bilangan bulat dan tanggal acak dalam rentang:
sumber
http://en.cppreference.com/w/cpp/numeric/random/rand
sumber
%6
.) Dan jika Anda memutuskan untuk menggunakanstd::rand
C ++ API darirand
fungsi pustaka C mengapa tidak menggunakanstd::time
danstd::srand
demi konsistensi gaya C ++?Bisa mendapatkan
Randomer
kode kelas penuh untuk menghasilkan angka acak dari sini!Jika Anda membutuhkan angka acak di bagian proyek yang berbeda, Anda dapat membuat kelas terpisah
Randomer
untuk merangkum semuarandom
hal di dalamnya.Sesuatu seperti itu:
Kelas seperti itu akan berguna nanti:
Anda dapat memeriksa link ini sebagai contoh bagaimana saya menggunakan seperti
Randomer
kelas untuk menghasilkan string acak. Anda juga dapat menggunakanRandomer
jika Anda mau.sumber
Gunakan skenario kasus
Saya menyamakan masalah Predictability dengan sekantong enam bit kertas, masing-masing dengan nilai dari 0 hingga 5 tertulis di atasnya. Selembar kertas diambil dari tas setiap kali nilai baru diperlukan. Jika tas kosong, maka nomor dimasukkan kembali ke dalam tas.
... dari ini, saya dapat membuat semacam algoritma.
Algoritma
Tas biasanya a
Collection
. Saya memilihbool[]
(atau dikenal sebagai array boolean, bit plane atau bit map) untuk mengambil peran tas.Alasan saya memilih
bool[]
adalah karena indeks setiap item sudah menjadi nilai dari setiap lembar kertas. Jika kertas-kertas itu membutuhkan apa pun yang tertulis di atasnya, maka saya akan menggunakannya sebagaiDictionary<string, bool>
gantinya. Nilai boolean digunakan untuk melacak apakah nomor telah ditarik atau belum.Penghitung dipanggil
RemainingNumberCount
diinisialisasi ke5
yang menghitung mundur sebagai nomor acak dipilih. Ini menyelamatkan kita dari keharusan menghitung berapa banyak kertas yang tersisa setiap kali kita ingin menggambar nomor baru.Untuk memilih nilai random berikutnya saya menggunakan
for..loop
untuk memindai melalui kantong indeks, dan counter untuk menghitung off ketikaindex
sedangfalse
disebutNumberOfMoves
.NumberOfMoves
digunakan untuk memilih nomor yang tersedia berikutnya.NumberOfMoves
pertama-tama ditetapkan sebagai nilai acak antara0
dan5
, karena ada 0..5 langkah yang tersedia yang dapat kita lakukan melalui tas. Pada iterasi berikutnyaNumberOfMoves
diatur menjadi nilai acak antara0
dan4
, karena sekarang ada 0,4 langkah yang bisa kita buat melalui tas. Karena angka-angka tersebut digunakan, angka-angka yang tersedia berkurang sehingga kami gunakanrand() % (RemainingNumberCount + 1)
untuk menghitung nilai selanjutnya untukNumberOfMoves
.Ketika
NumberOfMoves
penghitung mencapai nol,for..loop
harus sebagai berikut:for..loop
indeks.false
.for..loop
.Kode
Kode untuk solusi di atas adalah sebagai berikut:
(letakkan tiga blok berikut ke dalam file .cpp utama satu demi satu)
Kelas Konsol
Saya membuat kelas Konsol ini karena membuatnya mudah untuk mengarahkan ulang keluaran.
Di bawah ini dalam kode ...
... dapat diganti dengan ...
... dan kemudian
Console
kelas ini dapat dihapus jika diinginkan.Metode utama
Contoh penggunaan sebagai berikut:
Contoh output
Ketika saya menjalankan program, saya mendapat hasil sebagai berikut:
Pernyataan penutup
Program ini ditulis menggunakan Visual Studio 2017 , dan saya memilih untuk menjadikannya
Visual C++ Windows Console Application
proyek menggunakan.Net 4.6.1
.Saya tidak melakukan sesuatu yang istimewa di sini, jadi kodenya harus bekerja pada versi Visual Studio sebelumnya juga.
sumber
Setiap kali Anda melakukan pencarian web dasar
random number generation
dalam bahasa pemrograman C ++ pertanyaan ini biasanya yang pertama muncul! Saya ingin melemparkan topi saya ke atas ring untuk semoga lebih memperjelas konsep generasi nomor pseudo-acak di C ++ untuk coders masa depan yang pasti akan mencari pertanyaan yang sama di web!Dasar
Pembuatan bilangan pseudo-acak melibatkan proses penggunaan algoritma deterministik yang menghasilkan urutan angka yang propertinya kira-kira menyerupai bilangan acak . Saya kira kira mirip , karena keacakan yang sebenarnya adalah misteri yang agak sulit dipahami dalam matematika dan ilmu komputer. Oleh karena itu, mengapa istilah pseudo-acak digunakan untuk menjadi lebih benar secara pedantik!
Sebelum Anda benar-benar dapat menggunakan PRNG, yaitu,
pseudo-random number generator
Anda harus memberikan algoritma dengan nilai awal yang sering disebut juga seed . Namun, seed hanya harus diset satu kali sebelum menggunakan algoritma itu sendiri!Jadi, jika Anda menginginkan urutan angka yang baik, maka Anda harus memberikan benih yang cukup kepada PRNG!
Jalan C Lama
Pustaka standar yang kompatibel dengan C dari yang dimiliki C ++, menggunakan apa yang disebut generator kongruensial linier yang ditemukan di
cstdlib
file header! PRNG ini berfungsi melalui fungsi sambungan terputus-putus yang memanfaatkan aritmatika modular, yaitu algoritma cepat yang suka menggunakanmodulo operator '%'
. Berikut ini adalah penggunaan umum dari PRNG ini, sehubungan dengan pertanyaan awal yang diajukan oleh @Prediktabilitas:Penggunaan umum PRNG C menampung sejumlah masalah seperti:
std::rand()
tidak terlalu intuitif untuk menghasilkan angka pseudo-acak yang tepat antara rentang yang diberikan, misalnya, menghasilkan angka antara [1, 6] seperti yang diinginkan @Pictictability.std::rand()
menghilangkan kemungkinan distribusi seragam nomor pseudo-acak, karena Prinsip Pigeonhole .std::rand()
disemai secarastd::srand( ( unsigned int )std::time( nullptr ) )
teknis tidak benar, karenatime_t
dianggap sebagai tipe terbatas . Karenanya, konversi daritime_t
keunsigned int
tidak dijamin!Untuk informasi yang lebih terperinci tentang masalah keseluruhan penggunaan PRNG C, dan bagaimana cara menghindarinya, silakan merujuk ke Menggunakan rand () (C / C ++): Saran untuk fungsi rand () perpustakaan standar C !
Cara C ++ Standar
Sejak standar ISO / IEC 14882: 2011 diterbitkan, yaitu, C ++ 11,
random
perpustakaan telah terpisah dari bahasa pemrograman C ++ untuk sementara waktu sekarang. Perpustakaan ini dilengkapi dengan beberapa PRNGs, dan berbeda jenis distribusi seperti: distribusi seragam , distribusi normal , distribusi binomial , dll kode sumber berikut Contoh menunjukkan penggunaan yang sangat dasar darirandom
perpustakaan, berkaitan dengan @ pertanyaan awal Prediktabilitas ini:32-bit Mersenne Twister mesin, dengan distribusi seragam dari bilangan bulat nilai-nilai yang digunakan dalam contoh di atas. (Nama mesin dalam kode sumber terdengar aneh, karena namanya berasal dari periode 2 ^ 19937-1). Contoh ini juga digunakan
std::random_device
untuk seed engine, yang memperoleh nilainya dari sistem operasi (Jika Anda menggunakan sistem Linux, makastd::random_device
mengembalikan nilai dari/dev/urandom
).Perhatikan, bahwa Anda tidak harus menggunakan
std::random_device
untuk menabur mesin apa pun . Anda dapat menggunakan konstanta atau bahkanchrono
perpustakaan! Anda juga tidak harus menggunakanstd::mt19937
mesin versi 32-bit , ada opsi lain ! Untuk informasi lebih lanjut tentang kapabilitasrandom
perpustakaan, silakan merujuk ke cplusplus.comSecara keseluruhan, programmer C ++ seharusnya tidak menggunakan
std::rand()
lagi, bukan karena itu buruk , tetapi karena standar saat ini memberikan alternatif yang lebih baik yang lebih lurus dan dapat diandalkan . Semoga banyak dari Anda yang merasa terbantu, terutama Anda yang baru saja mencari di webgenerating random numbers in c++
!sumber
Ini solusinya. Buat fungsi yang mengembalikan angka acak dan letakkan di luar fungsi utama untuk menjadikannya global. Semoga ini membantu
sumber
Kode ini menghasilkan angka acak dari
n
hinggam
.contoh:
sumber
srand(time(0))
ke fungsi utama sebelumnyarandom(n, m)
?srand(time(0))
ke fungsi utama bukan untuk loop atau di dalam implementasi fungsi.untuk setiap file RUN acak
sumber
Berikut ini adalah generator acak sederhana dengan kira-kira. probabilitas yang sama untuk menghasilkan nilai positif dan negatif sekitar 0:
sumber