Berkaitan dengan rand() % n
kurang ideal
Melakukan rand() % n
memiliki distribusi yang tidak seragam. Anda akan mendapatkan jumlah nilai tertentu yang tidak proporsional karena jumlah nilai bukan kelipatan 20
Berikutnya, rand()
biasanya merupakan generator kongruensial linier (ada banyak yang lain , hanya ini yang paling mungkin diterapkan - dan dengan parameter yang kurang ideal (ada banyak cara untuk memilih parameter)). Masalah terbesar dengan ini adalah seringnya bit rendah di dalamnya (yang Anda dapatkan dengan % 20
ekspresi tipe) tidak acak. Saya ingat satu rand()
dari tahun lalu di mana bit terendah berganti dari 1
ke 0
dengan setiap panggilan ke rand()
- itu tidak terlalu acak.
Dari halaman manual rand (3):
Versi rand () dan srand () di Linux C Library menggunakan hal yang sama
generator angka acak sebagai acak () dan acak (), jadi urutan bawah
bit harus acak seperti bit orde tinggi. Namun, pada yang lebih tua
rand () implementasi, dan implementasi saat ini berbeda
sistem, bit orde rendah jauh lebih sedikit acak daripada yang lebih tinggi-
memesan bit. Jangan gunakan fungsi ini dalam aplikasi yang dimaksudkan
portabel saat keacakan dibutuhkan.
Ini mungkin sekarang diturunkan ke sejarah, tetapi sangat mungkin bahwa Anda masih memiliki implementasi rand () yang buruk yang tersembunyi di suatu tempat di stack. Dalam hal ini, masih cukup berlaku.
Yang harus dilakukan adalah benar-benar menggunakan pustaka angka acak yang baik (yang memberikan angka acak yang baik) dan kemudian meminta angka acak dalam rentang yang Anda inginkan.
Contoh bit kode acak yang bagus (mulai pukul 13:00 di video yang ditautkan)
#include <iostream>
#include <random>
int main() {
std::mt19937 mt(1729); // yes, this is a fixed seed
std::uniform_int_distribution<int> dist(0, 99);
for (int i = 0; i < 10000; i++) {
std::cout << dist(mt) << " ";
}
std::cout << std::endl;
}
Bandingkan ini dengan:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main() {
srand(time(NULL));
for (int i = 0; i < 10000; i++) {
printf("%d ", rand() % 100);
}
printf("\n");
}
Jalankan kedua program ini dan bandingkan seberapa sering angka-angka tertentu muncul (atau tidak muncul) dalam output itu.
Video terkait: rand () dianggap berbahaya
Beberapa aspek historis rand () yang menyebabkan bug di Nethack yang harus diperhatikan dan dipertimbangkan dalam implementasi sendiri:
Masalah Nethack RNG
Rand () adalah fungsi yang sangat mendasar untuk pembuatan angka acak Nethack. Cara Nethack menggunakannya adalah buggy atau dapat dikatakan bahwa lrand48 () menghasilkan angka pseudo-acak yang jelek. (Namun, lrand48 () adalah fungsi pustaka yang menggunakan metode PRNG yang ditentukan dan program apa pun yang menggunakannya harus memperhitungkan kelemahan metode itu.)
Bugnya adalah bahwa Nethack mengandalkan (kadang-kadang secara eksklusif seperti halnya dalam rn (2)) pada bit yang lebih rendah dari hasil dari lrand48 (). Karena itu, RNG di seluruh permainan bekerja buruk. Ini terutama terlihat sebelum tindakan pengguna memperkenalkan keacakan lebih lanjut, yaitu dalam pembuatan karakter dan pembuatan tingkat pertama.
Walaupun hal di atas berasal dari tahun 2003, hal itu harus tetap diingat karena mungkin tidak semua sistem yang menjalankan game yang Anda tuju akan menjadi sistem Linux terkini dengan fungsi rand () yang bagus.
Jika Anda hanya melakukan ini untuk diri sendiri, Anda dapat menguji seberapa baik generator nomor acak Anda dengan menulis beberapa kode dan menguji output dengan ent .
Pada sifat-sifat angka acak
Ada interpretasi lain 'acak' yang tidak sepenuhnya acak. Dalam aliran data acak, sangat mungkin untuk mendapatkan nomor yang sama dua kali. Jika Anda melempar koin (acak), sangat mungkin untuk mendapatkan dua kepala berturut-turut. Atau melempar dadu dua kali dan mendapatkan nomor yang sama dua kali berturut-turut. Atau memutar roda roulette dan mendapatkan nomor yang sama dua kali di sana.
Distribusi angka
Saat memainkan daftar lagu, orang berharap 'acak' berarti bahwa lagu atau artis yang sama tidak akan diputar untuk kedua kalinya berturut-turut. Memiliki daftar putar bermain The Beatles dua kali berturut-turut dianggap 'tidak acak' (meskipun adalah acak). Persepsi bahwa untuk daftar putar empat lagu diputar total delapan kali:
1 3 2 4 1 2 4 3
lebih 'acak' dari:
1 3 3 2 1 4 4 2
Lebih lanjut tentang ini untuk 'pengacakan' lagu: Bagaimana cara mengacak lagu?
Pada nilai yang diulang
Jika Anda tidak ingin mengulangi nilai, ada pendekatan berbeda yang harus dipertimbangkan. Hasilkan semua nilai yang mungkin, dan kocok.
Jika Anda menelepon rand()
(atau generator nomor acak lainnya), Anda memanggilnya dengan pengganti. Anda selalu bisa mendapatkan nomor yang sama dua kali. Satu opsi adalah membuang nilai berulang-ulang sampai Anda memilih satu yang memenuhi persyaratan Anda. Saya akan menunjukkan bahwa ini memiliki runtime non-determistic dan ada kemungkinan bahwa Anda dapat menemukan diri Anda dalam situasi di mana ada infinite loop kecuali Anda mulai melakukan penelusuran balik yang lebih kompleks.
Daftar dan Pilih
Pilihan lain adalah membuat daftar semua status yang mungkin valid dan kemudian memilih elemen acak dari daftar itu. Temukan semua tempat kosong (yang memenuhi beberapa aturan) di ruangan dan kemudian pilih satu yang acak dari daftar itu. Dan kemudian lakukan lagi dan lagi sampai selesai.
Acak
Pendekatan lain adalah mengocok seolah-olah setumpuk kartu. Mulailah dengan semua tempat kosong di ruangan itu dan kemudian mulai menugaskan mereka dengan membagikan tempat kosong, satu per satu, untuk setiap aturan / proses meminta tempat kosong. Anda selesai ketika Anda kehabisan kartu atau hal-hal berhenti meminta mereka.