Solusi Mark (Solusi yang diterima) Hampir Sempurna.
int x;
do {
x = rand();
} while (x >= (RAND_MAX - RAND_MAX % n));
x %= n;
diedit 25 Maret 16 jam 23:16
Mark Amery 39k21170211
Namun, ia memiliki peringatan yang membuang 1 set hasil yang valid dalam setiap skenario di mana RAND_MAX
( RM
) adalah 1 kurang dari kelipatan N
(Di mana N
= Jumlah hasil yang mungkin valid).
yaitu, ketika 'jumlah nilai yang dibuang' ( D
) sama dengan N
, maka mereka sebenarnya adalah set yang valid ( V)
, bukan set yang tidak valid ( I
).
Apa yang menyebabkan ini pada beberapa titik Mark kehilangan pandangan tentang perbedaan antara N
dan Rand_Max
.
N
adalah himpunan yang anggotanya valid hanya terdiri dari Bilangan Bulat Positif, karena berisi hitungan tanggapan yang akan valid. (mis .: Set N
= {1, 2, 3, ... n }
)
Rand_max
Namun adalah himpunan yang (sebagaimana didefinisikan untuk tujuan kami) termasuk sejumlah bilangan bulat non-negatif.
Dalam bentuk yang paling umum, apa yang didefinisikan di sini Rand Max
adalah Himpunan semua hasil yang valid, yang secara teoritis dapat mencakup angka negatif atau nilai-nilai non-numerik.
Oleh karena Rand_Max
itu lebih baik didefinisikan sebagai set "Kemungkinan Tanggapan".
Namun N
beroperasi terhadap penghitungan nilai dalam set tanggapan yang valid, sehingga meskipun seperti yang didefinisikan dalam kasus khusus kami, Rand_Max
akan menjadi nilai yang kurang dari jumlah total yang dikandungnya.
Menggunakan Mark's Solution, Nilai Dihapus ketika: X => RM - RM% N
EG:
Ran Max Value (RM) = 255
Valid Outcome (N) = 4
When X => 252, Discarded values for X are: 252, 253, 254, 255
So, if Random Value Selected (X) = {252, 253, 254, 255}
Number of discarded Values (I) = RM % N + 1 == N
IE:
I = RM % N + 1
I = 255 % 4 + 1
I = 3 + 1
I = 4
X => ( RM - RM % N )
255 => (255 - 255 % 4)
255 => (255 - 3)
255 => (252)
Discard Returns $True
Seperti yang Anda lihat dalam contoh di atas, ketika nilai X (angka acak yang kita dapatkan dari fungsi awal) adalah 252, 253, 254, atau 255 kita akan membuangnya meskipun keempat nilai ini terdiri dari sekumpulan nilai yang dikembalikan. .
IE: Ketika penghitungan nilai Diabaikan (I) = N (Jumlah hasil yang valid) maka seperangkat nilai pengembalian yang valid akan dibuang oleh fungsi asli.
Jika kita menggambarkan perbedaan antara nilai N dan RM sebagai D, yaitu:
D = (RM - N)
Kemudian ketika nilai D menjadi lebih kecil, Persentase roll-ulang yang tidak dibutuhkan karena metode ini meningkat pada setiap multiplikatif alami. (Ketika RAND_MAX TIDAK sama dengan Nomor Perdana, ini menjadi perhatian yang sah)
MISALNYA:
RM=255 , N=2 Then: D = 253, Lost percentage = 0.78125%
RM=255 , N=4 Then: D = 251, Lost percentage = 1.5625%
RM=255 , N=8 Then: D = 247, Lost percentage = 3.125%
RM=255 , N=16 Then: D = 239, Lost percentage = 6.25%
RM=255 , N=32 Then: D = 223, Lost percentage = 12.5%
RM=255 , N=64 Then: D = 191, Lost percentage = 25%
RM=255 , N= 128 Then D = 127, Lost percentage = 50%
Karena persentase Rerolls yang dibutuhkan meningkat semakin dekat N datang ke RM, ini dapat menjadi perhatian yang valid pada banyak nilai yang berbeda tergantung pada kendala sistem yang menjalankan kode dan nilai-nilai yang dicari.
Untuk meniadakan hal ini, kita dapat membuat amandemen sederhana.
int x;
do {
x = rand();
} while (x > (RAND_MAX - ( ( ( RAND_MAX % n ) + 1 ) % n) );
x %= n;
Ini memberikan versi formula yang lebih umum yang menjelaskan keanehan tambahan menggunakan modulus untuk menentukan nilai maksimal Anda.
Contoh menggunakan nilai kecil untuk RAND_MAX yang merupakan multiplikasi dari N.
Versi Asli:
RAND_MAX = 3, n = 2, Values in RAND_MAX = 0,1,2,3, Valid Sets = 0,1 and 2,3.
When X >= (RAND_MAX - ( RAND_MAX % n ) )
When X >= 2 the value will be discarded, even though the set is valid.
Versi Umum 1:
RAND_MAX = 3, n = 2, Values in RAND_MAX = 0,1,2,3, Valid Sets = 0,1 and 2,3.
When X > (RAND_MAX - ( ( RAND_MAX % n ) + 1 ) % n )
When X > 3 the value would be discarded, but this is not a vlue in the set RAND_MAX so there will be no discard.
Selain itu, dalam hal N harus menjadi jumlah nilai dalam RAND_MAX; dalam hal ini, Anda dapat mengatur N = RAND_MAX +1, kecuali RAND_MAX = INT_MAX.
Namun, Anda hanya bisa menggunakan N = 1, dan nilai X apa pun akan diterima, dan masukkan pernyataan IF untuk pengali akhir Anda. Tetapi mungkin Anda memiliki kode yang mungkin memiliki alasan yang valid untuk mengembalikan 1 ketika fungsi dipanggil dengan n = 1 ...
Jadi mungkin lebih baik menggunakan 0, yang biasanya memberikan Div 0 Error, ketika Anda ingin memiliki n = RAND_MAX + 1
Versi Umum 2:
int x;
if n != 0 {
do {
x = rand();
} while (x > (RAND_MAX - ( ( ( RAND_MAX % n ) + 1 ) % n) );
x %= n;
} else {
x = rand();
}
Kedua solusi ini menyelesaikan masalah dengan hasil valid yang tidak perlu dibuang yang akan terjadi ketika RM + 1 adalah produk dari n.
Versi kedua juga mencakup skenario tepi ketika Anda perlu n untuk menyamakan total set nilai yang mungkin terkandung dalam RAND_MAX.
Pendekatan yang dimodifikasi pada keduanya sama dan memungkinkan solusi yang lebih umum untuk kebutuhan menyediakan angka acak yang valid dan meminimalkan nilai yang dibuang.
Untuk mengulangi:
Solusi Umum Dasar yang mencakup contoh tanda:
// Assumes:
// RAND_MAX is a globally defined constant, returned from the environment.
// int n; // User input, or externally defined, number of valid choices.
int x;
do {
x = rand();
} while (x > (RAND_MAX - ( ( ( RAND_MAX % n ) + 1 ) % n) ) );
x %= n;
Solusi Umum yang Diperpanjang yang Memungkinkan satu skenario tambahan RAND_MAX + 1 = n:
// Assumes:
// RAND_MAX is a globally defined constant, returned from the environment.
// int n; // User input, or externally defined, number of valid choices.
int x;
if n != 0 {
do {
x = rand();
} while (x > (RAND_MAX - ( ( ( RAND_MAX % n ) + 1 ) % n) ) );
x %= n;
} else {
x = rand();
}
Dalam beberapa bahasa (terutama bahasa yang ditafsirkan) melakukan perhitungan operasi perbandingan di luar kondisi sementara dapat menyebabkan hasil yang lebih cepat karena ini adalah perhitungan satu kali tidak peduli berapa banyak percobaan ulang diperlukan. YMMV!
// Assumes:
// RAND_MAX is a globally defined constant, returned from the environment.
// int n; // User input, or externally defined, number of valid choices.
int x; // Resulting random number
int y; // One-time calculation of the compare value for x
if n != 0 {
y = RAND_MAX - ( ( ( RAND_MAX % n ) + 1 ) % n)
do {
x = rand();
} while (x > y);
x %= n;
} else {
x = rand();
}
RAND_MAX%n == n - 1
_ adalah(RAND_MAX + 1) % n == 0
. Saat membaca kode, saya cenderung memahami% something == 0
"terbagi rata" lebih mudah daripada cara lain untuk menghitungnya. Tentu saja, jika stdlib C ++ Anda memilikiRAND_MAX
nilai yang samaINT_MAX
,(RAND_MAX + 1)
tentu tidak akan berfungsi; jadi perhitungan Markus tetap merupakan implementasi teraman.