Bagaimana cara menghasilkan float acak di C ++?
Saya pikir saya bisa mengambil bilangan bulat rand dan membaginya dengan sesuatu, apakah itu cukup?
c++
random
floating-point
Hasen
sumber
sumber
random
header yang ditambahkan dalam C ++ 11 semakin didukung oleh dokumen standar N3924: Discouraging rand () dalam C ++ 14 . Saya memasukkanrand()
jawaban saya untuk sebagian besar pertimbangan historis tetapi juga menyadari aplikasi warisan memang ada.<random>
tajukJawaban:
rand()
dapat digunakan untuk menghasilkan angka pseudo-acak di C ++. Dalam kombinasi denganRAND_MAX
dan sedikit matematika, Anda dapat menghasilkan angka acak dalam interval sewenang-wenang yang Anda pilih. Ini cukup untuk tujuan pembelajaran dan program mainan. Jika Anda benar - benar membutuhkan angka acak dengan distribusi normal, Anda harus menggunakan metode yang lebih maju.Ini akan menghasilkan angka dari 0,0 hingga 1,0, inklusif.
Ini akan menghasilkan nomor dari 0,0 ke beberapa sewenang-wenang
float
,X
:Ini akan menghasilkan angka dari beberapa arbitrer
LO
ke beberapa arbitrerHI
:Perhatikan bahwa
rand()
fungsi ini sering tidak memadai jika Anda membutuhkan angka acak.Sebelum menelepon
rand()
, Anda harus terlebih dahulu "seed" generator nomor acak dengan meneleponsrand()
. Ini harus dilakukan sekali selama menjalankan program Anda - tidak setiap kali Anda meneleponrand()
. Ini sering dilakukan seperti ini:Untuk menelepon
rand
atausrand
Anda harus#include <cstdlib>
.Untuk menelepon
time
, Anda harus#include <ctime>
.sumber
rand()
. Pertanyaan ini, dan jawaban saya, secara khusus berfokus pada mempelajari dasar-dasarnya dan tidak mementingkan tingkat presisi yang tinggi. Anda harus belajar berjalan sebelum belajar berlari.C ++ 11 memberi Anda banyak opsi baru
random
. Makalah kanonik pada topik ini adalah N3551, Random Number Generation dalam C ++ 11Untuk melihat mengapa menggunakan
rand()
bisa menjadi masalah, lihat rand () Dianggap bahan presentasi Berbahaya oleh Stephan T. Lavavej yang diberikan selama acara GoingNative 2013 . Slide ada di komentar tetapi di sini ada tautan langsung .Saya juga membahas
boost
dan menggunakanrand
karena kode lawas mungkin masih memerlukan dukungannya.Contoh di bawah ini disaring dari situs cppreference dan menggunakan mesin std :: mersenne_twister_engine dan std :: uniform_real_distribution yang menghasilkan angka dalam
[0,10)
interval, dengan mesin dan distribusi lain dikomentari ( lihat langsung ):output akan mirip dengan yang berikut:
Output akan bervariasi tergantung pada distribusi yang Anda pilih, jadi jika kami memutuskan untuk pergi dengan std :: normal_distribution dengan nilai
2
untuk mean dan stddev misalnyadist(2, 2)
outputnya akan mirip dengan ini ( lihat langsung ):Berikut ini adalah versi modifikasi dari beberapa kode yang disajikan dalam
N3551
( lihat langsung ):Hasil akan terlihat mirip dengan:
Dorongan
Tentu saja Boost.Random selalu menjadi pilihan juga, di sini saya menggunakan boost :: random :: uniform_real_distribution :
rand ()
Jika Anda harus menggunakan
rand()
maka kita bisa pergi ke FAQ C untuk panduan tentang Bagaimana saya bisa menghasilkan angka acak floating-point? , yang pada dasarnya memberikan contoh yang mirip dengan ini untuk menghasilkan suatu interval[0,1)
:dan untuk menghasilkan angka acak dalam kisaran dari
[M,N)
:sumber
randMToN
pls kamu ? catat baik itu[M,N]
atau tambahkan kembali+ 1.
dari yang di atasrandZeroToOne
. -> pikirkan menyebutnya seperti ini:randMToN(0.0, 1.0);
(N-M)
. Cara yang baik untuk mengatasi kesalahan ini dapat ditemukan di sini: stackoverflow.com/questions/33058848/...Lihatlah Boost.Random . Anda dapat melakukan sesuatu seperti ini:
Bermain-main, Anda mungkin lebih baik melewati objek mt19937 yang sama di sekitar daripada membangun yang baru setiap kali, tapi mudah-mudahan Anda mendapatkan idenya.
sumber
max
tetapi dapat menggunakan terbukamin
, Anda dapat membalikkan interval dengan mudah:return min + max - gen();
.Di modern,
c++
Anda dapat menggunakan<random>
tajuk yang disertakanc++11
.Untuk mendapatkan secara acak
float
Anda dapat menggunakanstd::uniform_real_distribution<>
.Anda dapat menggunakan fungsi untuk menghasilkan angka dan jika Anda tidak ingin angka sama setiap saat, atur mesin dan distribusinya
static
.Contoh:
Ini sangat ideal untuk menempatkan
float
's dalam wadah sepertistd::vector
:Contoh output:
sumber
std::uniform_real_distribution<> dis(0, 1); // rage 0 - 1
secara teknis salah, 1.0 tidak akan pernah dihasilkan, lihat en.cppreference.com/w/cpp/numeric/random/…To create a distribution over the closed interval [a,b], std::nextafter(b, std::numeric_limits<RealType>::max()) may be used as the second parameter.
Panggil kode dengan dua
float
nilai, kode tersebut bekerja dalam kisaran apa pun.sumber
fmaf()
(atau floatfma()
overload di C ++) di C99 atau C ++ 11, yang mungkin lebih presisi. Seperti dalamfmaf((float)rand() / RAND_MAX, b - a, a)
,.Jika Anda menggunakan C ++ dan bukan C, maka ingatlah bahwa dalam laporan teknis 1 (TR1) dan dalam konsep C ++ 0x mereka telah menambahkan fasilitas untuk generator angka acak dalam file header, saya percaya itu identik dengan Boost. Pustaka acak dan jelas lebih fleksibel dan "modern" daripada fungsi pustaka C, rand.
Sintaks ini menawarkan kemampuan untuk memilih generator (seperti mersenne twister mt19937) dan kemudian memilih distribusi (normal, bernoulli, binomial dll.).
Sintaksnya adalah sebagai berikut (tanpa malu-malu meminjam dari situs ini ):
sumber
Pada beberapa sistem (Windows dengan VC muncul dalam pikiran, saat ini),
RAND_MAX
sangat kecil, i. e. hanya 15 bit. Ketika membaginya denganRAND_MAX
Anda hanya menghasilkan mantissa 15 bit, bukan 23 bit yang mungkin. Ini mungkin atau mungkin bukan masalah bagi Anda, tetapi Anda kehilangan beberapa nilai dalam kasus itu.Oh, perhatikan saja sudah ada komentar untuk masalah itu. Bagaimanapun, berikut ini beberapa kode yang mungkin bisa menyelesaikan masalah ini untuk Anda:
Belum diuji, tetapi mungkin berhasil :-)
sumber
drand48(3)
adalah cara standar POSIX. GLibC juga menyediakan versi reentrantdrand48_r(3)
,.Fungsi ini dinyatakan usang dalam SVID 3 tetapi tidak ada alternatif yang memadai disediakan sehingga IEEE Std 1003.1-2013 masih memasukkannya dan tidak memiliki catatan bahwa itu akan terjadi di mana saja dalam waktu dekat.
Di Windows, cara standarnya adalah CryptGenRandom () .
sumber
Saya tidak puas dengan salah satu jawaban sejauh ini jadi saya menulis fungsi float acak baru. Itu membuat asumsi bitwise tentang tipe data float. Masih membutuhkan fungsi rand () dengan setidaknya 15 bit acak.
sumber
Menurut pendapat saya jawaban di atas memang memberikan beberapa float 'acak', tetapi tidak satupun dari mereka benar-benar float acak (yaitu mereka kehilangan bagian dari representasi float). Sebelum saya akan terburu-buru dalam implementasi saya mari kita lihat format standar ANSI / IEEE untuk float:
| tanda (1-bit) | e (8-bit) | f (23-bit) |
angka yang diwakili oleh kata ini adalah (-1 * masuk) * 2 ^ e * 1.f
catat nomor 'e' adalah nomor bias (dengan bias 127) sehingga berkisar dari -127 hingga 126. Fungsi yang paling sederhana (dan sebenarnya paling acak) adalah dengan hanya menulis data dari int acak ke float, jadi
perhatikan bahwa jika Anda melakukannya
float f = (float)rand();
akan mengubah bilangan bulat menjadi float (dengan demikian 10 akan menjadi 10.0).Jadi sekarang jika Anda ingin membatasi nilai maksimum, Anda dapat melakukan sesuatu seperti (tidak yakin apakah ini berfungsi)
tetapi jika Anda melihat struktur float, Anda dapat melihat bahwa nilai maksimum float adalah (kira-kira) 2 ^ 127 yang jauh lebih besar dari nilai maksimum int (2 ^ 32) sehingga mengesampingkan bagian penting dari float. angka-angka yang dapat diwakili oleh pelampung. Ini adalah implementasi terakhir saya:
menggunakan fungsi ini
randf(0, 8, 0)
akan mengembalikan angka acak antara 0,0 dan 255,0sumber
int e = (rand() % (max_exp - min_exp)) + min_exp_mod;
dan mantra:int f = (int)(frac_mod * (float)rand() / RAND_MAX);
mengganti baris masing-masing di atas. Perhatikan bahwa kesalahan mantissa adalah besar: untuk yangRAND_MAX
lebih kecil1 << 23
Anda hanya akan mengacak bit signifikan yang lebih rendah dan mendapatkan 0 untuk bit yang paling signifikan sepanjang waktu!Jika Anda tahu bahwa format floating point Anda adalah IEEE 754 (hampir semua CPU modern termasuk Intel dan ARM) maka Anda dapat membuat angka floating point acak dari integer acak menggunakan metode bit-wise. Ini hanya dapat dipertimbangkan jika Anda tidak memiliki akses ke C ++ 11
random
atauBoost.Random
yang keduanya jauh lebih baik.Ini akan memberikan distribusi yang lebih baik daripada divisi yang menggunakan.
sumber
return (float)random23 / (1 << 23)
. (Ya, saya baru saja menguji ini , memodifikasi fungsi Anda untuk mengambilrandom32
sebagai parameter dan menjalankannya untuk semua nilai dari nol hingga(1 << 23)-1
. Dan ya, metode Anda memang memberikan hasil yang persis sama dengan pembagian oleh1 << 23
.)Untuk C ++, ini dapat menghasilkan angka float nyata dalam rentang yang ditentukan oleh
dist
variabelsumber
rand () mengembalikan int antara 0 dan RAND_MAX. Untuk mendapatkan angka acak antara 0,0 dan 1,0, pertama-tama masukkan int return dengan rand () ke float, lalu bagi dengan RAND_MAX.
sumber
Saya tidak dapat memposting dua jawaban, jadi inilah solusi kedua. nomor acak log2, bias masif menuju 0,0f tetapi ini benar-benar float 1.0f hingga 0.0f.
sumber