Zufällige Erzeugung von Gleitkommazahlen

271

Wie generiere ich zufällige Floats in C ++?

Ich dachte, ich könnte den ganzzahligen Rand nehmen und ihn durch etwas teilen. Wäre das ausreichend?

hasen
quelle
2
Es kommt eher darauf an, wofür Sie die Nummer wollen und wie zufällig. Normalerweise gibt rand () 15 Bit Zufälligkeit aus, aber Floats haben eine Genauigkeit von 23 Bit, sodass einige Werte fehlen.
Pete Kirkham
1
Ich habe meine Antwort aktualisiert, um alle wichtigen verfügbaren Optionen einzuschließen, und meine Entscheidung, mich auf randomdie in C ++ 11 hinzugefügten Header zu konzentrieren, wird durch das Standarddokument N3924: Discouraging rand () in C ++ 14 weiter gestärkt . Ich beziehe rand()in meine Antwort hauptsächlich historische Überlegungen ein, aber auch die Realisierung einer Legacy-Anwendung.
Shafik Yaghmour
Meine Antwort beinhaltet, wie man vermeidet, jedes Mal die gleichen Zahlen mit dem <random>Header zu bekommen
Andreas DM

Antworten:

381

rand()kann verwendet werden, um Pseudozufallszahlen in C ++ zu generieren. In Kombination mit RAND_MAXund ein wenig Mathematik können Sie Zufallszahlen in einem beliebigen Intervall generieren. Dies reicht für Lernzwecke und Spielzeugprogramme aus. Wenn Sie wirklich zufällige Zahlen mit normaler Verteilung benötigen, müssen Sie eine fortgeschrittenere Methode anwenden.


Dadurch wird eine Zahl von 0,0 bis einschließlich 1,0 generiert.

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

Dies wird eine Zahl von 0,0 bis zu einem gewissen willkürlichen erzeugen float, X:

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

Dies erzeugt eine Zahl von willkürlich LOzu willkürlich HI:

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

Beachten Sie, dass die rand()Funktion oft nicht ausreicht, wenn Sie wirklich zufällige Zahlen benötigen.


Bevor Sie anrufen rand(), müssen Sie zuerst den Zufallszahlengenerator durch Aufrufen "setzen" srand(). Dies sollte einmal während der Ausführung Ihres Programms erfolgen - nicht einmal bei jedem Aufruf rand(). Dies geschieht oft so:

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

Um anzurufen randoder srandmüssen Sie #include <cstdlib>.

Um anzurufen time, müssen Sie #include <ctime>.

John Dibling
quelle
22
Vergessen Sie nicht, zuerst zu säen!
Klaim
14
Am besten ist zu beachten, dass beide Grenzwerte inklusive sind.
dmckee --- Ex-Moderator Kätzchen
14
Diese Antwort ist irreführend. Es wurde letzte Woche auf der Going Native 2013 behandelt. rand () Als schädlich eingestuft, channel9.msdn.com/Events/GoingNative/2013/… für eine sehr detaillierte Erklärung.
Ade Miller
14
Ich verstehe nicht, warum so viele Leute diese Antwort positiv bewertet haben. Es ist mathematisch falsch. RAND_MAX ist eine sehr kleine Zahl (normalerweise 2 ^ 16). Das bedeutet, dass Sie aus 23 Bits des Gleitkommas nur 15 zufällige machen. Die anderen werden wahrscheinlich Null sein. Sie erhalten zwar Zufallszahlen in gleichmäßiger Verteilung, aber von geringer Genauigkeit. Zum Beispiel kann Ihr Zufallsgenerator 0,00001 und 0,00002 generieren, aber nicht 0,000017. Sie haben also eine gleichmäßige Verteilung, aber eine geringe Genauigkeit (256-mal weniger Genauigkeit als der tatsächliche Gleitkomma).
DanielHsH
10
@DanielHsH: Das OP fragte speziell, mit welcher Mechanik zufällige Floats erzeugt werden könnten rand(). Diese Frage und meine Antwort konzentrierten sich speziell auf das Erlernen der Grundlagen und waren nicht besorgt über ein hohes Maß an Präzision. Sie müssen laufen lernen, bevor Sie laufen lernen können.
John Dibling
137

C ++ 11 bietet Ihnen viele neue Optionen mit random. Das kanonische Papier zu diesem Thema wäre N3551, Random Number Generation in C ++ 11

Um zu sehen, warum die Verwendung rand()problematisch sein kann, lesen Sie das Rand () als schädliches Präsentationsmaterial von Stephan T. Lavavej, das während der GoingNative 2013- Veranstaltung gegeben wurde. Die Folien sind in den Kommentaren, aber hier ist ein direkter Link .

Ich gehe boostauch auf die Verwendung ein, randda Legacy-Code möglicherweise noch Unterstützung benötigt.

Das folgende Beispiel wurde von der cppreference-Site destilliert und verwendet die std :: mersenne_twister_engine- Engine und die std :: uniform_real_distribution, die im [0,10)Intervall Zahlen generiert , wobei andere Engines und Distributionen auskommentiert werden ( siehe live ):

#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';
    }
}

Die Ausgabe ähnelt der folgenden:

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

Der Ausgang wird variieren je nachdem , welche Distribution Sie wählen, so dass , wenn wir mit gehen entschieden std :: normal_distribution mit einem Wert von 2sowohl mittleren und stddev zB dist(2, 2)anstelle der Ausgang wäre ähnlich wie diesen ( siehe es leben ):

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

Das Folgende ist eine modifizierte Version eines Teils des Codes, der in N3551( siehe live ) vorgestellt wird:

#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;
}

Die Ergebnisse sehen ähnlich aus wie:

5H 5S AS 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

Boost

Natürlich ist Boost.Random auch immer eine Option, hier verwende ich 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 ()

Wenn Sie verwenden müssen, rand()finden Sie in den C-FAQ eine Anleitung zum Wie kann ich Gleitkomma-Zufallszahlen generieren? , die im Grunde ein ähnliches Beispiel für die Erzeugung eines Intervalls gibt [0,1):

#include <stdlib.h>

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

und um eine Zufallszahl im Bereich von zu generieren [M,N):

double randMToN(double M, double N)
{
    return M + (rand() / ( RAND_MAX / (N-M) ) ) ;  
}
Shafik Yaghmour
quelle
1
können Sie Ihre randMToNpls reparieren? Beachten Sie entweder, dass es ist, [M,N]oder fügen Sie das + 1.von oben hinzu randZeroToOne. -> denken Sie daran, es so zu nennen:randMToN(0.0, 1.0);
BeyelerStudios
1
Seien Sie auch vorsichtig mit der Division durch Null bei (N-M). Eine gute
Dr. Beco
61

Schauen Sie sich Boost.Random an . Sie könnten so etwas tun:

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();
}

Spielen Sie herum, vielleicht ist es besser, dasselbe mt19937-Objekt herumzugeben, als jedes Mal ein neues zu erstellen, aber hoffentlich haben Sie die Idee.

rlbond
quelle
1
uniform_real verwendet ein halboffenes Intervall [min, max], was bedeutet, dass Sie Ihren Minimalwert erhalten, aber niemals den Maximalwert erreichen. Es ist etwas zu beachten, obwohl Sie dieses Problem überwinden können, wenn Sie auf irgendeine Weise herumrunden.
TehWan
20
Dies ist jetzt Teil von C ++ 11.
Tomas Andrle
@Wolf In praktischen Anwendungen ist die Wahrscheinlichkeit, einen bestimmten Gleitkommawert zu erreichen, so gering, dass es keine Rolle spielt, ob der Endpunkt eingeschlossen oder ausgeschlossen wird. Wenn Sie maxein offenes Ende benötigen, aber verwenden können min, können Sie das Intervall einfach umkehren : return min + max - gen();.
Mark Ransom
26

In der Moderne können c++Sie den <random>mitgelieferten Header verwenden c++11.
Um zufällige zu erhalten float, können Sie verwendenstd::uniform_real_distribution<> .

Sie können eine Funktion verwenden, um die Zahlen zu generieren. Wenn Sie nicht möchten, dass die Zahlen immer gleich sind , stellen Sie die Engine und die Verteilung so ein static.
Beispiel:

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

Es ist ideal, die floatin einen Behälter zu legen , wie zum Beispiel 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 << " ";
}

Beispielausgabe:

0.0518757 0.969106 0.0985112 0.0895674 0.895542
Andreas DM
quelle
std::uniform_real_distribution<> dis(0, 1); // rage 0 - 1ist technisch nicht korrekt, 1.0 wird niemals generiert, siehe 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
Dies sollte die akzeptierte Antwort sein, es ist verdammt 2020.
Alex
25

Rufen Sie den Code mit zwei floatWerten auf, der Code funktioniert in einem beliebigen Bereich.

float rand_FloatRange(float a, float b)
{
    return ((b - a) * ((float)rand() / RAND_MAX)) + a;
}
Ivan Prodanov
quelle
Es kann erwähnenswert sein, dass dies ein potenzieller Anwendungsfall für fmaf()(oder die Float- fma()Überladung in C ++) in C99 oder C ++ 11 ist, wodurch möglicherweise mehr Präzision erhalten bleibt. Wie in , fmaf((float)rand() / RAND_MAX, b - a, a).
Tim
22

Wenn Sie C ++ und nicht C verwenden, denken Sie daran, dass im technischen Bericht 1 (TR1) und im C ++ 0x-Entwurf Funktionen für einen Zufallszahlengenerator in der Header-Datei hinzugefügt wurden. Ich glaube, dass dieser mit dem Boost identisch ist. Zufällige Bibliothek und definitiv flexibler und "moderner" als die C-Bibliotheksfunktion, Rand.

Diese Syntax bietet die Möglichkeit, einen Generator (wie den Mersenne-Twister mt19937) und anschließend eine Verteilung (Normal, Bernoulli, Binomial usw.) auszuwählen.

Die Syntax lautet wie folgt (schamlos von dieser Site entlehnt ):

  #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
quelle
2
Dies ist jetzt in C ++ 11, auch dist kann mit einem Min- und Max-Wert initialisiert werden.
Étienne
Es erscheint mir seltsam, Min und Max in den Initialisierer zu setzen und den Generator bereitzustellen, wenn ein Wert ermittelt wird - ich würde es vorziehen, wenn es umgekehrt wäre, na ja.
Jojo
6

Auf einigen Systemen (Windows mit VC fällt derzeit ein) RAND_MAXist lächerlich klein, d.h. e. nur 15 bit. Wenn RAND_MAXSie durch dividieren, erzeugen Sie nur eine Mantisse von 15 Bit anstelle der 23 möglichen Bits. Dies kann ein Problem für Sie sein oder auch nicht, aber in diesem Fall fehlen Ihnen einige Werte.

Oh, habe gerade bemerkt, dass es bereits einen Kommentar zu diesem Problem gab. Wie auch immer, hier ist ein Code, der dies für Sie lösen könnte:

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

Ungetestet, könnte aber funktionieren :-)

Joey
quelle
Was ist mit float r = (float) ((rand () << 9) | rand ()) / RAND_MAX? (auch ungetestet)
Falle
Argh, sorry, das Teilen durch RAND_MAX bringt dich nirgendwo hin ... der springende Punkt bei diesem Trick war, etwas zu haben, das größer als RAND_MAX ist ... das wurde auch für mich behoben.
Joey
2
Seien Sie vorsichtig beim Erstellen von Zufallszahlen ohne Theorie ... aufeinanderfolgende Aufrufe von rand () sind möglicherweise nicht vollständig unabhängig. Hinweis: Wenn es sich um einen linearen Kongruenzgenerator handelt, beobachten Sie das niedrige Bit bei aufeinanderfolgenden Aufrufen: Es wechselt zwischen 0 und 1.
RBerteig
Ich weiß. Für einige Anwendungen kann dies jedoch ausreichen. Aber ja, in diesem Fall sollten Sie wahrscheinlich mehr als nur zwei Anrufe verwenden. In diesem Fall gibt es keine Silberkugel, Sie können sich nicht einmal darauf verlassen, dass es sich um eine LCG handelt. Andere PRNGs haben schwache hohe Bits. Die Boost-Lösung sollte hier die beste sein.
Joey
(nb: Das von rand in MSVC zurückgegebene niedrige Bit ist nicht das niedrigste Bit des RNG-Status. Für 100 rand () -Aufrufe erhalte ich Folgendes: ähnlich zu machen)
Joey
4

drand48(3)ist der POSIX-Standardweg. GLibC bietet auch eine wiedereintrittsfähige Version drand48_r(3).

Die Funktion wurde in SVID 3 für veraltet erklärt, es wurde jedoch keine angemessene Alternative bereitgestellt, sodass IEEE Std 1003.1-2013 sie weiterhin enthält und keine Hinweise darauf enthält, dass sie bald irgendwohin geht.

In Windows ist CryptGenRandom () der Standard .

ivan_pozdeev
quelle
2

Bisher war ich mit keiner der Antworten zufrieden, daher habe ich eine neue zufällige Float-Funktion geschrieben. Es werden bitweise Annahmen über den Float-Datentyp getroffen. Es benötigt noch eine rand () - Funktion mit mindestens 15 zufälligen Bits.

//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
quelle
7
interessanter Ansatz, ich würde gerne upvoten, aber ich verstehe wirklich nicht, was los ist
hasen
2

Meiner Meinung nach gibt die obige Antwort einen 'zufälligen' Float, aber keiner von ihnen ist wirklich ein zufälliger Float (dh sie vermissen einen Teil der Float-Darstellung). Bevor ich mich mit meiner Implementierung befasse, werfen wir zunächst einen Blick auf das ANSI / IEEE-Standardformat für Floats:

| Vorzeichen (1 Bit) | e (8 Bit) | f (23 Bit) |

Die durch dieses Wort dargestellte Zahl ist (-1 * Vorzeichen) * 2 ^ e * 1.f.

Beachten Sie, dass die 'e'-Zahl eine voreingenommene (mit einer Vorspannung von 127) Zahl ist, die von -127 bis 126 reicht. Die einfachste (und tatsächlich zufälligste) Funktion besteht darin, nur die Daten eines zufälligen int in einen float zu schreiben. so

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

Beachten Sie, float f = (float)rand();dass in diesem Fall die Ganzzahl in einen Gleitkommawert umgewandelt wird (10 wird also zu 10,0).

Wenn Sie nun den Maximalwert begrenzen möchten, können Sie Folgendes tun (nicht sicher, ob dies funktioniert).

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

Wenn Sie sich jedoch die Struktur des Floats ansehen, können Sie sehen, dass der Maximalwert eines Floats (ungefähr) 2 ^ 127 beträgt, was viel größer ist als der Maximalwert eines Int (2 ^ 32), wodurch ein wesentlicher Teil von ausgeschlossen wird die Zahlen, die durch einen Float dargestellt werden können. Dies ist meine endgültige Implementierung:

/**
 * 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;
}

Bei Verwendung dieser Funktion randf(0, 8, 0)wird eine Zufallszahl zwischen 0,0 und 255,0 zurückgegeben

user2546926
quelle
1
Du hast einen Fehler. rand ()% frac_mod funktioniert nicht, da MAX_RAND normalerweise niedriger als (1 << 23) ist.
DanielHsH
Ich muss zugeben, dass ich die genaue Größe von MAX_RAND nicht kenne. Trotzdem wird es immer noch funktionieren, es ist vielleicht eine nutzlose Aussage, aber es wird immer noch funktionieren. 8% 10 = 8, das ist in Ordnung, aber wenn MAX_RAND immer kleiner als (1 << 23) ist, können Sie es tatsächlich entfernen.
user2546926
2
Nein, du liegst ein bisschen falsch. RandMax ist normalerweise ~ 65.000. Das bedeutet, dass Sie aus 23 Bits nur 15 zufällige machen. Die anderen werden wahrscheinlich Null sein. Sie erhalten zwar Zufallszahlen, aber von geringer Genauigkeit. Zum Beispiel kann Ihr Zufallsgenerator 0,001 und 0,002 generieren, aber nicht 0,0017. Sie haben also eine gleichmäßige Verteilung, aber eine geringe Genauigkeit (256-mal weniger genau als der Schwimmer).
DanielHsH
Diese Antwort enthält zwei Fehler. Festlegen des Exponentenbereichs: int e = (rand() % (max_exp - min_exp)) + min_exp_mod;und der Mantisse: int f = (int)(frac_mod * (float)rand() / RAND_MAX);Ersetzen der jeweiligen Zeilen oben. Beachten Sie, dass der Mantissenfehler schwerwiegend ist: Bei RAND_MAXkleineren 1 << 23Bits würden Sie nur die niedrigstwertigen Bits zufällig sortieren und die ganze Zeit 0s für die höchstwertigen Bits erhalten!
BeyelerStudios
2

Wenn Sie wissen, dass Ihr Gleitkommaformat IEEE 754 ist (fast alle modernen CPUs, einschließlich Intel und ARM), können Sie eine zufällige Gleitkommazahl aus einer zufälligen Ganzzahl mit bitweisen Methoden erstellen. Dies sollte nur berücksichtigt werden, wenn Sie keinen Zugriff auf C ++ 11 haben randomoder Boost.Randombeide viel besser sind.

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;
}

Dies ergibt eine bessere Verteilung als eine mit Division.

Mark Ransom
quelle
8
Ich bin mir nicht sicher, warum Sie sagen, dass dies eine "bessere Verteilung" ergeben würde. In der Tat ergibt dies genau die gleiche Verteilung wie gerade return (float)random23 / (1 << 23). (Ja, ich habe dies gerade getestet , Ihre Funktion so geändert, dass sie random32als Parameter verwendet wird, und sie für alle Werte von Null bis ausgeführt (1 << 23)-1. Und ja, Ihre Methode liefert tatsächlich genau die gleichen Ergebnisse wie die Division durch 1 << 23.)
Ilmari Karonen
1

Für C ++ können echte Gleitkommazahlen innerhalb des durch die distVariable angegebenen Bereichs generiert werden

#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
quelle
1
Haben Sie gerade den Code aus dieser Antwort kopiert und eingefügt? stackoverflow.com/a/1118739/1538531
Derek
Eigentlich nein. Ich bin etwas überrascht zu sehen, wie sehr sie sich ähneln! Aber ich habe den Motorgenerator am 1. Januar 1970 initialisiert.
Marco167
Meinetwegen. Ich habe bemerkt, dass Sie den Generator auf die Epoche initialisiert haben, aber verdammt, dieser Code ist ähnlich!
Derek
Ich finde es etwas seltsam, ein TR1-Beispiel zu geben. Können Sie erklären, in welchen Fällen jemand TR1 im Gegensatz zu C ++ 11 verwenden müsste?
Shafik Yaghmour
0

rand () gibt ein int zwischen 0 und RAND_MAX zurück. Um eine Zufallszahl zwischen 0,0 und 1,0 zu erhalten, wandeln Sie zuerst die int-Rückgabe mit rand () in einen float um und dividieren Sie dann durch RAND_MAX.

James Curran
quelle
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));
...

Ich konnte keine zwei Antworten posten, daher hier die zweite Lösung. log2 Zufallszahlen, massive Tendenz zu 0.0f, aber es ist wirklich ein zufälliger Float 1.0f bis 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
quelle