Pembuatan angka float acak

271

Bagaimana cara menghasilkan float acak di C ++?

Saya pikir saya bisa mengambil bilangan bulat rand dan membaginya dengan sesuatu, apakah itu cukup?

Hasen
sumber
2
Tergantung pada apa yang Anda inginkan nomornya, dan seberapa acak. biasanya rand () akan memberikan 15 bit keacakan, tetapi float memiliki presisi 23 bit, sehingga akan kehilangan beberapa nilai.
Pete Kirkham
1
Saya telah memperbarui jawaban saya untuk memasukkan semua opsi utama yang tersedia dan pilihan saya untuk fokus pada randomheader yang ditambahkan dalam C ++ 11 semakin didukung oleh dokumen standar N3924: Discouraging rand () dalam C ++ 14 . Saya memasukkan rand()jawaban saya untuk sebagian besar pertimbangan historis tetapi juga menyadari aplikasi warisan memang ada.
Shafik Yaghmour
Jawaban saya mencakup cara menghindari mendapatkan angka yang sama setiap kali dengan <random>tajuk
Andreas DM

Jawaban:

381

rand()dapat digunakan untuk menghasilkan angka pseudo-acak di C ++. Dalam kombinasi dengan RAND_MAXdan 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.

float r = static_cast <float> (rand()) / static_cast <float> (RAND_MAX);

Ini akan menghasilkan nomor dari 0,0 ke beberapa sewenang-wenang float, X:

float r2 = static_cast <float> (rand()) / (static_cast <float> (RAND_MAX/X));

Ini akan menghasilkan angka dari beberapa arbitrer LOke beberapa arbitrer HI:

float r3 = LO + static_cast <float> (rand()) /( static_cast <float> (RAND_MAX/(HI-LO)));

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 menelepon srand(). Ini harus dilakukan sekali selama menjalankan program Anda - tidak setiap kali Anda menelepon rand(). Ini sering dilakukan seperti ini:

srand (static_cast <unsigned> (time(0)));

Untuk menelepon randatau srandAnda harus #include <cstdlib>.

Untuk menelepon time, Anda harus #include <ctime>.

John Dibling
sumber
22
Jangan lupa untuk menabur dulu!
Klaim
14
Yang terbaik untuk dicatat bahwa kedua batasan tersebut inklusif.
dmckee --- ex-moderator kitten
14
Jawaban ini menyesatkan. Itu diliput di Going Native 2013 minggu lalu; rand () Dianggap Berbahaya, channel9.msdn.com/Events/GoingNative/2013/… untuk penjelasan yang sangat terperinci.
Ade Miller
14
Saya tidak mengerti mengapa begitu banyak orang yang mengangkat jawaban ini. Secara matematis salah. RAND_MAX adalah angka yang sangat kecil (biasanya 2 ^ 16). Itu berarti bahwa dari 23 bit titik apung yang Anda buat hanya 15 acak. Yang lain mungkin akan nol. Anda memang akan mendapatkan angka acak dalam distribusi seragam tetapi presisi rendah. Misalnya generator acak Anda dapat menghasilkan 0,00001 dan 0,00002 tetapi tidak dapat menghasilkan 0,000017. Jadi, Anda memiliki distribusi yang seragam tetapi presisi rendah (presisi 256 kali lebih sedikit daripada floating point yang sebenarnya).
DanielHsH
10
@DanielHsH: OP secara khusus menanyakan mekanis apa yang dapat digunakan untuk menghasilkan float acak 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.
John Dibling
137

C ++ 11 memberi Anda banyak opsi baru random. Makalah kanonik pada topik ini adalah N3551, Random Number Generation dalam C ++ 11

Untuk 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 boostdan menggunakan randkarena 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 ):

#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <random>

int main()
{
    std::random_device rd;

    //
    // Engines 
    //
    std::mt19937 e2(rd());
    //std::knuth_b e2(rd());
    //std::default_random_engine e2(rd()) ;

    //
    // Distribtuions
    //
    std::uniform_real_distribution<> dist(0, 10);
    //std::normal_distribution<> dist(2, 2);
    //std::student_t_distribution<> dist(5);
    //std::poisson_distribution<> dist(2);
    //std::extreme_value_distribution<> dist(0,2);

    std::map<int, int> hist;
    for (int n = 0; n < 10000; ++n) {
        ++hist[std::floor(dist(e2))];
    }

    for (auto p : hist) {
        std::cout << std::fixed << std::setprecision(1) << std::setw(2)
                  << p.first << ' ' << std::string(p.second/200, '*') << '\n';
    }
}

output akan mirip dengan yang berikut:

0 ****
1 ****
2 ****
3 ****
4 *****
5 ****
6 *****
7 ****
8 *****
9 ****

Output akan bervariasi tergantung pada distribusi yang Anda pilih, jadi jika kami memutuskan untuk pergi dengan std :: normal_distribution dengan nilai 2untuk mean dan stddev misalnya dist(2, 2)outputnya akan mirip dengan ini ( lihat langsung ):

-6 
-5 
-4 
-3 
-2 **
-1 ****
 0 *******
 1 *********
 2 *********
 3 *******
 4 ****
 5 **
 6 
 7 
 8 
 9 

Berikut ini adalah versi modifikasi dari beberapa kode yang disajikan dalam N3551( lihat langsung ):

#include <algorithm>
#include <array>
#include <iostream>
#include <random>

std::default_random_engine & global_urng( )
{
    static std::default_random_engine u{};
    return u ;
}

void randomize( )
{
    static std::random_device rd{};
    global_urng().seed( rd() );
}

int main( )
{
  // Manufacture a deck of cards:
  using card = int;
  std::array<card,52> deck{};
  std::iota(deck.begin(), deck.end(), 0);

  randomize( ) ;  

  std::shuffle(deck.begin(), deck.end(), global_urng());
  // Display each card in the shuffled deck:
  auto suit = []( card c ) { return "SHDC"[c / 13]; };
  auto rank = []( card c ) { return "AKQJT98765432"[c % 13]; };

  for( card c : deck )
      std::cout << ' ' << rank(c) << suit(c);

   std::cout << std::endl;
}

Hasil akan terlihat mirip dengan:

5H 5 S SEBAGAI 9S 4D 6H TH 6D KH 2S QS 9H 8H 3D KC TD 7H 2D KS 3C TC 7D 4C QH QC QD JD AH JC AC KD 9D 5C 2H 4H 9C 8C JH 5D 4S 7C AD 3S 8S TS 2C 8D 3H 6C JS 7S 6S

Dorongan

Tentu saja Boost.Random selalu menjadi pilihan juga, di sini saya menggunakan boost :: random :: uniform_real_distribution :

#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_real_distribution.hpp>

int main()
{
    boost::random::mt19937 gen;
    boost::random::uniform_real_distribution<> dist(0, 10);

    std::map<int, int> hist;
    for (int n = 0; n < 10000; ++n) {
        ++hist[std::floor(dist(gen))];
    }

    for (auto p : hist) {
        std::cout << std::fixed << std::setprecision(1) << std::setw(2)
                  << p.first << ' ' << std::string(p.second/200, '*') << '\n';
    }
}

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):

#include <stdlib.h>

double randZeroToOne()
{
    return rand() / (RAND_MAX + 1.);
}

dan untuk menghasilkan angka acak dalam kisaran dari [M,N):

double randMToN(double M, double N)
{
    return M + (rand() / ( RAND_MAX / (N-M) ) ) ;  
}
Shafik Yaghmour
sumber
1
dapatkah kamu memperbaiki randMToNpls kamu ? catat baik itu [M,N]atau tambahkan kembali + 1.dari yang di atas randZeroToOne. -> pikirkan menyebutnya seperti ini:randMToN(0.0, 1.0);
BeyelerStudios
1
Juga berhati-hatilah dengan pembagian dengan nol pada (N-M). Cara yang baik untuk mengatasi kesalahan ini dapat ditemukan di sini: stackoverflow.com/questions/33058848/...
Dr Beco
61

Lihatlah Boost.Random . Anda dapat melakukan sesuatu seperti ini:

float gen_random_float(float min, float max)
{
    boost::mt19937 rng;
    boost::uniform_real<float> u(min, max);
    boost::variate_generator<boost::mt19937&, boost::uniform_real<float> > gen(rng, u);
    return gen();
}

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.

rbbond
sumber
1
uniform_real menggunakan interval setengah terbuka [min, maks), yang berarti Anda akan mendapatkan nilai minimum Anda tetapi tidak akan pernah mencapai nilai maksimum. Ini sesuatu yang perlu dipertimbangkan, meskipun jika Anda membulatkan tekad, Anda dapat mengatasi masalah ini.
TehWan
20
Ini sekarang bagian dari C ++ 11.
Tomas Andrle
@Wolf dalam aplikasi praktis, kemungkinan memukul nilai floating point tertentu sangat rendah sehingga tidak masalah jika titik akhir disertakan atau dikecualikan. Jika Anda membutuhkan maxtetapi dapat menggunakan terbuka min, Anda dapat membalikkan interval dengan mudah: return min + max - gen();.
Mark Ransom
26

Di modern, c++Anda dapat menggunakan <random>tajuk yang disertakan c++11.
Untuk mendapatkan secara acak floatAnda dapat menggunakan std::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:

float get_random()
{
    static std::default_random_engine e;
    static std::uniform_real_distribution<> dis(0, 1); // rage 0 - 1
    return dis(e);
}

Ini sangat ideal untuk menempatkan float's dalam wadah seperti std::vector:

int main()
{
    std::vector<float> nums;
    for (int i{}; i != 5; ++i) // Generate 5 random floats
        nums.emplace_back(get_random());

    for (const auto& i : nums) std::cout << i << " ";
}

Contoh output:

0.0518757 0.969106 0.0985112 0.0895674 0.895542
Andreas DM
sumber
std::uniform_real_distribution<> dis(0, 1); // rage 0 - 1secara 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.
Troyseph
1
Ini harus menjadi jawaban yang diterima, ini menakutkan tahun 2020.
Alex
25

Panggil kode dengan dua floatnilai, kode tersebut bekerja dalam kisaran apa pun.

float rand_FloatRange(float a, float b)
{
    return ((b - a) * ((float)rand() / RAND_MAX)) + a;
}
Ivan Prodanov
sumber
Mungkin perlu disebutkan bahwa ini adalah kasus penggunaan potensial untuk fmaf()(atau float fma()overload di C ++) di C99 atau C ++ 11, yang mungkin lebih presisi. Seperti dalam fmaf((float)rand() / RAND_MAX, b - a, a),.
Tim Čas
22

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 ):

  #include <iostream>
  #include <random>

  ...

  std::tr1::mt19937 eng;  // a core engine class 
  std::tr1::normal_distribution<float> dist;     

  for (int i = 0; i < 10; ++i)        
      std::cout << dist(eng) << std::endl;
Rick
sumber
2
Ini sekarang di C ++ 11, juga dist dapat diinisialisasi dengan nilai min dan max.
Étienne
Rasanya aneh bagi saya untuk meletakkan min dan max di inisialisasi dan menyediakan generator ketika mendapatkan nilai - saya lebih suka jika itu sebaliknya, oh well.
yoyo
6

Pada beberapa sistem (Windows dengan VC muncul dalam pikiran, saat ini), RAND_MAXsangat kecil, i. e. hanya 15 bit. Ketika membaginya dengan RAND_MAXAnda 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:

float r = (float)((rand() << 15 + rand()) & ((1 << 24) - 1)) / (1 << 24);

Belum diuji, tetapi mungkin berhasil :-)

Joey
sumber
Bagaimana dengan float r = (float) ((rand () << 9) | rand ()) / RAND_MAX? (juga belum diuji)
Perangkap
Argh, maaf, membagi dengan RAND_MAX tidak akan membawamu ke mana pun ... inti dari trik ini adalah memiliki sesuatu yang lebih besar daripada RAND_MAX ... memperbaikinya juga untukku.
Joey
2
Hati-hati menyusun angka acak tanpa teori ... panggilan beruntun ke rand () mungkin tidak sepenuhnya independen. Petunjuk: jika ini merupakan generator kongruensial linier, perhatikan bit rendah pada panggilan berurutan: ia berganti-ganti antara 0 dan 1.
RBerteig
Aku tahu. Untuk beberapa aplikasi, ini mungkin cukup. Tapi ya, Anda mungkin harus menggunakan lebih dari dua panggilan dalam kasus ini. Tidak ada peluru perak dalam kasus ini, Anda bahkan tidak bisa mengandalkannya sebagai LCG. PRNG lain memiliki bit tinggi yang lemah. Solusi Peningkatan harus menjadi yang terbaik di sini.
Joey
(nb: Bit rendah yang dikembalikan oleh rand di MSVC bukan bit terendah dari negara RNG. Untuk 100 rand () panggilan saya mendapatkan yang berikut: 11001000001111111010100100100110101010101111111100100000010101000011011000000100101100011. Java hanya menggunakan bit-bit untuk melakukan hal yang sama)
Joey
4

drand48(3)adalah cara standar POSIX. GLibC juga menyediakan versi reentrant drand48_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 () .

ivan_pozdeev
sumber
2

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.

//Returns a random number in the range [0.0f, 1.0f).  Every
//bit of the mantissa is randomized.
float rnd(void){
  //Generate a random number in the range [0.5f, 1.0f).
  unsigned int ret = 0x3F000000 | (0x7FFFFF & ((rand() << 8) ^ rand()));
  unsigned short coinFlips;

  //If the coin is tails, return the number, otherwise
  //divide the random number by two by decrementing the
  //exponent and keep going. The exponent starts at 63.
  //Each loop represents 15 random bits, a.k.a. 'coin flips'.
  #define RND_INNER_LOOP() \
    if( coinFlips & 1 ) break; \
    coinFlips >>= 1; \
    ret -= 0x800000
  for(;;){
    coinFlips = rand();
    RND_INNER_LOOP(); RND_INNER_LOOP(); RND_INNER_LOOP();
    //At this point, the exponent is 60, 45, 30, 15, or 0.
    //If the exponent is 0, then the number equals 0.0f.
    if( ! (ret & 0x3F800000) ) return 0.0f;
    RND_INNER_LOOP(); RND_INNER_LOOP(); RND_INNER_LOOP();
    RND_INNER_LOOP(); RND_INNER_LOOP(); RND_INNER_LOOP();
    RND_INNER_LOOP(); RND_INNER_LOOP(); RND_INNER_LOOP();
    RND_INNER_LOOP(); RND_INNER_LOOP(); RND_INNER_LOOP();
  }
  return *((float *)(&ret));
}
iNFiNiTyLoOp
sumber
7
pendekatan yang menarik, saya ingin upvote tapi, aku benar-benar tidak mengerti apa yang terjadi
hasen
2

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

int tmp = rand();
float f = (float)*((float*)&tmp);

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)

int tmp = rand();
float f = *((float*)&tmp);
tmp = (unsigned int)f       // note float to int conversion!
tmp %= max_number;
f -= tmp;

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:

/**
 * Function generates a random float using the upper_bound float to determine 
 * the upper bound for the exponent and for the fractional part.
 * @param min_exp sets the minimum number (closest to 0) to 1 * e^min_exp (min -127)
 * @param max_exp sets the maximum number to 2 * e^max_exp (max 126)
 * @param sign_flag if sign_flag = 0 the random number is always positive, if 
 *              sign_flag = 1 then the sign bit is random as well
 * @return a random float
 */
float randf(int min_exp, int max_exp, char sign_flag) {
    assert(min_exp <= max_exp);

    int min_exp_mod = min_exp + 126;

    int sign_mod = sign_flag + 1;
    int frac_mod = (1 << 23);

    int s = rand() % sign_mod;  // note x % 1 = 0
    int e = (rand() % max_exp) + min_exp_mod;
    int f = rand() % frac_mod;

    int tmp = (s << 31) | (e << 23) | f;

    float r = (float)*((float*)(&tmp));

    /** uncomment if you want to see the structure of the float. */
//    printf("%x, %x, %x, %x, %f\n", (s << 31), (e << 23), f, tmp, r);

    return r;
}

menggunakan fungsi ini randf(0, 8, 0)akan mengembalikan angka acak antara 0,0 dan 255,0

pengguna2546926
sumber
1
kamu memiliki kesalahan. rand ()% frac_mod tidak akan berfungsi karena MAX_RAND biasanya lebih rendah dari (1 << 23).
DanielHsH
Saya harus mengakui bahwa saya tidak tahu ukuran pasti MAX_RAND. Meskipun demikian itu masih akan bekerja, itu mungkin pernyataan yang tidak berguna, tetapi masih akan bekerja. 8% 10 = 8 jadi tidak masalah, tetapi jika MAX_RAND selalu lebih kecil maka (1 << 23) Anda memang bisa menghapusnya.
user2546926
2
Tidak, Anda sedikit salah. RandMax biasanya ~ 65.000. Itu berarti bahwa dari 23 bit Anda hanya membuat 15 bit. Yang lain mungkin akan nol. Anda memang akan mendapatkan angka acak tetapi presisi rendah. Misalnya generator acak Anda dapat menghasilkan 0,001 dan 0,002 tetapi tidak dapat menghasilkan 0,0017. Jadi Anda memiliki distribusi yang seragam tetapi presisi rendah (presisi 256 kali lebih sedikit daripada float).
DanielHsH
Ada dua kesalahan dalam jawaban ini. Memperbaiki rentang eksponen: 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 yang RAND_MAXlebih kecil 1 << 23Anda hanya akan mengacak bit signifikan yang lebih rendah dan mendapatkan 0 untuk bit yang paling signifikan sepanjang waktu!
BeyelerStudios
2

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 randomatau Boost.Randomyang keduanya jauh lebih baik.

float rand_float()
{
    // returns a random value in the range [0.0-1.0)

    // start with a bit pattern equating to 1.0
    uint32_t pattern = 0x3f800000;

    // get 23 bits of random integer
    uint32_t random23 = 0x7fffff & (rand() << 8 ^ rand());

    // replace the mantissa, resulting in a number [1.0-2.0)
    pattern |= random23;

    // convert from int to float without undefined behavior
    assert(sizeof(float) == sizeof(uint32_t));
    char buffer[sizeof(float)];
    memcpy(buffer, &pattern, sizeof(float));
    float f;
    memcpy(&f, buffer, sizeof(float));

    return f - 1.0;
}

Ini akan memberikan distribusi yang lebih baik daripada divisi yang menggunakan.

Mark tebusan
sumber
8
Saya tidak yakin mengapa Anda mengatakan ini akan memberikan "distribusi yang lebih baik". Bahkan, ini akan memberikan distribusi yang sama persis dengan adil return (float)random23 / (1 << 23). (Ya, saya baru saja menguji ini , memodifikasi fungsi Anda untuk mengambil random32sebagai parameter dan menjalankannya untuk semua nilai dari nol hingga (1 << 23)-1. Dan ya, metode Anda memang memberikan hasil yang persis sama dengan pembagian oleh 1 << 23.)
Ilmari Karonen
1

Untuk C ++, ini dapat menghasilkan angka float nyata dalam rentang yang ditentukan oleh distvariabel

#include <random>  //If it doesnt work then use   #include <tr1/random>
#include <iostream>

using namespace std;

typedef std::tr1::ranlux64_base_01 Myeng; 
typedef std::tr1::normal_distribution<double> Mydist;

int main() { 
       Myeng eng; 
       eng.seed((unsigned int) time(NULL)); //initializing generator to January 1, 1970);
       Mydist dist(1,10); 

       dist.reset(); // discard any cached values 
       for (int i = 0; i < 10; i++)
       {
           std::cout << "a random value == " << (int)dist(eng) << std::endl; 
       }

       return (0);
}
Marco167
sumber
1
Apakah Anda hanya menyalin dan menempelkan kode dari jawaban ini? stackoverflow.com/a/1118739/1538531
Derek
Sebenarnya Tidak. Saya sedikit terkejut melihat betapa miripnya mereka! Tapi saya menginisialisasi mesin-generator Jan 1.1970.
Marco167
Cukup adil. Saya memang memperhatikan bahwa Anda menginisialisasi generator ke zaman, tetapi sangat mirip dengan kode itu!
Derek
Saya merasa sedikit aneh untuk memberikan contoh TR1, dapatkah Anda menjelaskan dalam kasus apa seseorang harus menggunakan TR1 sebagai lawan dari C ++ 11?
Shafik Yaghmour
0

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.

James Curran
sumber
0
#include <cstdint>
#include <cstdlib>
#include <ctime>

using namespace std;

/* single precision float offers 24bit worth of linear distance from 1.0f to 0.0f */
float getval() {
    /* rand() has min 16bit, but we need a 24bit random number. */
    uint_least32_t r = (rand() & 0xffff) + ((rand() & 0x00ff) << 16);
    /* 5.9604645E-8 is (1f - 0.99999994f), 0.99999994f is the first value less than 1f. */
    return (double)r * 5.9604645E-8;
}

int main()
{
    srand(time(NULL));
...

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.

#include <cstdint>
#include <cstdlib>
#include <ctime>

using namespace std;

float getval () {
    union UNION {
        uint32_t i;
        float f;
    } r;
    /* 3 because it's 0011, the first bit is the float's sign.
     * Clearing the second bit eliminates values > 1.0f.
     */
    r.i = (rand () & 0xffff) + ((rand () & 0x3fff) << 16);
    return r.f;
}

int main ()
{
    srand (time (NULL));
...
Mike Mestnik
sumber