# Zufallszahl zwischen 1 und 20.



## Stella74 (3. Januar 2017)

Hallo Leute,
ich habe gerade eben angefangen mich mit dem Programmieren auseinander zu setzten und habe mit C++ begonnen. Ich habe mir ein kleines "Programm" ohne wirklichen Sinn ausgedacht, welches bis jetzt so aussieht: 

```
#include <iostream>
using namespace std;

int main(){
    int x = 17;
    int Zahl = 0;
    cout<<"Raten Sie eine Zahl zwischen 1 und 20!"<<endl;
    cin>>Zahl;
    if (Zahl == x){
        cout<<"Sie haben die richtige Zahl gefunden! :)";
    }
    else{
        if(Zahl>17){
            cout<<"Sie haben verloren. Die gesuchte Zahl ist kleiner.";
        }
        else{
            cout<<"Sie haben verloren. Die gesuchte Zahl ist groeßer.";
        }
    }
}
```

Das funktioniert auch alles, doch jetzt möchte ich das "int x = 17" zu einer Zufallszahl machen. Wie funktioniert das? Kann mir da jemand helfen?

PS: Sorry, es gibt sicherlich schon ähnliche Themen.


----------



## cwriter (3. Januar 2017)

Hi



Stella74 hat gesagt.:


> Kann mir da jemand helfen?





Stella74 hat gesagt.:


> PS: Sorry, es gibt sicherlich schon ähnliche Themen.


http://www.cplusplus.com/reference/random/

Bei diesem Thema ist es allerdings gut, fragst du nach - gerade über die Zufallszahlen steht viel Stuss im Netz. Für dich das Beispiel vom Link entsprechend angepasst:

```
std::default_random_engine generator;
std::uniform_int_distribution<int> distribution(1,20);
int dice_roll = distribution(generator);  // generates number in the range 1..20
```

Damit solltest du in dice_roll Werte in [1, 20] (int) bekommen. (#include <random> nicht vergessen)

Gruss
cwriter


----------



## Stella74 (3. Januar 2017)

Erstmal vielen Dank für die schnelle Antwort. Ich habe es mal so eingetippt. Allerdings öffnet er jetzt eine neue Quelldatei die das beinhaltet:


----------



## cwriter (3. Januar 2017)

Stella74 hat gesagt.:


> Allerdings öffnet er jetzt eine neue Quelldatei die das beinhaltet:


Oh nein, nicht Dev-C++ schon wieder 
(Die IDE wurde von den Toten erweckt)
Falls es dich beruhigt: Ich habe damals(TM) mit Bloodshed Dev-C++ mit C begonnen.
Falls du die Möglichkeit hast, auf Visual Studio oder eine andere IDE wie QtCreator umzusteigen, würde ich das ins Auge fassen. Ansonsten gibt es noch die Möglichkeit, MinGW auf eine aktuelle Version zu bringen. Allerdings war das letzte Update auf Sourceforge im Jahr 2013...
@sheel: Habe ich etwas verpasst? Ist MinGW tot?

BackToTopic:
Falls du auf den alten und vergleichsweise mühsamen C-Weg ausweichen willst:

```
//#include <time.h> hinzufügen
srand(time(NULL));
int x = (rand() % 19) + 1;
```

Gruss
cwriter

/EDIT: Hehe.
http://www.cplusplus.com/doc/tutorial/introduction/devcpp/
Setze dort (wie beim Link geschrieben) den Standard auf c++11, dann sollte auch der C++-Code gehen.


----------



## Stella74 (3. Januar 2017)

Oh okay vielen Dank. ich schaue mal was ich bekomme.


----------



## sheel (3. Januar 2017)

Hi



cwriter hat gesagt.:


> Habe ich etwas verpasst? Ist MinGW tot?


Einiges  ... und jein.

Zu DevCPP: Keine Ahnung obs verwendbar und zeitgemäß ist, aber tot ist es nicht (schon länger nicht mehr):
https://sourceforge.net/projects/orwelldevcpp/

Zu MinGW: Das eigentliche "MinGW" ist tot, keine Ahnung warum und wie das passiert ist (Konnte es nie herausfinden; hab allerdings auch kein Monat herumgesucht).
"MinGW-W64" lebt, hat sowohl 32 als auch 64 bit (das Alte hatte nur 32), weiter verbesserte/erweiterte WInapi-Unterstützung, natürlich aktuellere Toolchains und deren C++-Versions-Unterstützungen, usw.usw.
https://mingw-w64.org/doku.php

Zum Zufallsthema zurück, @Stella74
Der C-Weg (und teilweise auch default_random_engine) macht keine "guten" Zufallszahlen. "Falls" es ein Problem ist, dass sich die Zahlen zB. nach 65000 Zufallszahlen wiederholen anfangen, und/oder manche Zahlen öfter vorkommen als andere (statt gleichverteilt), usw., dann besser MersenneTwister (MT) anschauen. Gibts auch im random-Include, einfach default_random_engine mit mt19937 ersetzen.

Und falls man irgendwann etwas kryptographisches vorhat, dran denken dass auch MT nicht sicher ist. MT ist zwar auf den ersten Blick schön zufällig, und für viele Anwedungen mehr als genug, aber wenn man ein paar erzeugte Zahlen weiß und auch ein bisschen Intelligenz hat kann man die nächste Zahl voraussagen. Wenn das nicht akzeptabel ist, wirds umständlicher....


----------



## cwriter (3. Januar 2017)

sheel hat gesagt.:


> Einiges





sheel hat gesagt.:


> Zu DevCPP: Keine Ahnung obs verwendbar und zeitgemäß ist, aber tot ist es nicht (mehr):


Daher auch


cwriter hat gesagt.:


> (Die IDE wurde von den Toten erweckt)



Zur Verwendbarkeit: Es ist schon länger her, seit ich Orwelldevcpp zuletzt verwendet habe (2014 vielleicht?), aber damals konnte ich keinen grossen Unterschied zum alten (2006er Bloodshed DevCpp) erkennen (ausser dem saulahmen Class Explorer) - vielleicht hat sich etwas mehr getan, aber wirklich gutes habe ich auch nicht gehört - es wurde schlicht (wirklich) still... Und es gibt mit VS und Qt wesentlich bessere IDEs, gerade unter Windows.



sheel hat gesagt.:


> Und falls man irgendwann etwas kryptographisches vorhat, dran denken dass auch MT nicht sicher ist. MT ist zwar auf den ersten Blick schön zufällig, und für viele Anwedungen mehr als genug, aber wenn man ein paar erzeugte Zahlen weiß und auch ein bisschen Intelligenz hat kann man die nächste Zahl voraussagen. Wenn das nicht akzeptabel ist, wirds umständlicher....


Bei Kryptographie sind eh ganz andere Libraries (OpenSSL/LibreSSL und Co) von Nöten. Aber schön, dass du es sicherheitshalber erwähnst 
Ob MT wirklich mehr bringt als die default_engine (gerade bei kleinen Bereichen wie 1..20)? Jetzt müsste ich nachlesen, wie der uniform_distributor funktioniert... Wird aber schon auch Modulo sein, oder?

Gruss
cwriter


----------



## sheel (3. Januar 2017)

Wenn Default=Linearkongruenz dann ist es eigentlich egal, ob Modulo oder nicht; gegen zB. die kurze Periodenlänge hilfts nicht. Und auch Modulo kann eine schlechte Verteilung (meistens) nicht verbessern

Jedenfalls, "ob" es Modulo ist ... ob sich hinter den ganzen Typen, Funktionen, Intrinsics und was auch immer ein Modulo versteckt, such ich jetzt lieber nicht 

```
template<typename _IntType>
 template<typename _UniformRandomNumberGenerator>
   typename uniform_int_distribution<_IntType>::result_type
   uniform_int_distribution<_IntType>::
   operator()(_UniformRandomNumberGenerator& __urng,
      const param_type& __param)
   {
 typedef typename std::make_unsigned<typename
   _UniformRandomNumberGenerator::result_type>::type __urngtype;
 typedef typename std::make_unsigned<result_type>::type __utype;
 typedef typename std::conditional<(sizeof(__urngtype)
                    > sizeof(__utype)),
   __urngtype, __utype>::type __uctype;

 const __uctype __urngmin = __urng.min();
 const __uctype __urngmax = __urng.max();
 const __uctype __urngrange = __urngmax - __urngmin;
 const __uctype __urange
   = __uctype(__param.b()) - __uctype(__param.a());

 __uctype __ret;

 if (__urngrange > __urange)
   {
     // downscaling
     const __uctype __uerange = __urange + 1; // __urange can be zero
     const __uctype __scaling = __urngrange / __uerange;
     const __uctype __past = __uerange * __scaling;
     do
       __ret = __uctype(__urng()) - __urngmin;
     while (__ret >= __past);
     __ret /= __scaling;
   }
 else if (__urngrange < __urange)
   {
     // upscaling
     /*
       Note that every value in [0, urange]
       can be written uniquely as

       (urngrange + 1) * high + low

       where

       high in [0, urange / (urngrange + 1)]

       and
 
       low in [0, urngrange].
     */
     __uctype __tmp; // wraparound control
     do
       {
     const __uctype __uerngrange = __urngrange + 1;
     __tmp = (__uerngrange * operator()
          (__urng, param_type(0, __urange / __uerngrange)));
     __ret = __tmp + (__uctype(__urng()) - __urngmin);
       }
     while (__ret > __urange || __ret < __tmp);
   }
 else
   __ret = __uctype(__urng()) - __urngmin;

 return __ret + __param.a();
   }
```
(https://gcc.gnu.org/onlinedocs/gcc-4.6.3/libstdc++/api/a00998_source.html 832)

(irgendwie geht beim Copypaste mit Links heute immer was daneben...)


----------



## cwriter (3. Januar 2017)

sheel hat gesagt.:


> Jedenfalls, "ob" es Modulo ist ... ob sich hinter den ganzen Typen, Funktionen, Intrinsics und was auch immer ein Modulo versteckt, such ich jetzt lieber nicht


Sieht nach dem "Umgekehrten" des Modulo aus (zumindest beim Downscaling):
rngrange = Range des Generators
urange = Range des Distributors (+1, da 0 sein könnte)
randnum = Zufallszahl

past = urange * (rngrange / urange) //Rest fällt in der Klammer weg (int-div)

Dann wird nach einer Zahl gesucht (in einem Loop... Wenn man Pech hat, läuft das recht lange (unwahrscheinlich  )), die kleiner als "past" ist und diese wird dann durch scaling (= (rngrange/urange) ) geteilt (und zum Minimum des Distributors addiert).

Als Beispiel (hauptsächlich als Gedankenstütze für mich  )
Falls rngrange = 1000 (0-1000), urange = 10 (0-9)
Dann ist scaling = 100 (kein Rest...)
Das erste Resultat der Schleife wird genommen und durch 100 geteilt.
Ich würfle mal voll zufällig eine 6. Dann wäre das Resultat 0
Dann wären die ersten 100 Zahlen eine 0, die zweiten 100 Zahlen eine 1 usw.

Oh ich weiss...

Es wird wohl nicht mit Modulo gemacht, da die höchsten Segmente nicht "vollständig" sein müssen; als Beispiel:
rngrange = 15, urange = 10
Dann wäre scaling = 1.
Und solange die "halben" Werte 10-15 erreicht werden, wird eine neue Zahl gewürfelt, da sonst die Wahrscheinlichkeit für 0-5 doppelt so gross wäre. Dieses Problem würde Modulo nicht beheben.

Allerdings bleibt anzumerken, dass wahrscheinlich rngrange >> urange gilt und der Effekt bei einem Modulo verschwindend gering sein sollte, und beim Modulo dafür ein bisschen Zeit gespart gespart wird.
Sagen wir als Beispiel Zufallszahlen mit short-Entropie, 65536. Bei Modulo (auf C-Weg) wären es bei einer Range von 0-10 6553 gültige und 1 ungültiger Wertebereich, d.h. 1/6554 Werten ist "falsch", was ~0.02% sind. Die Zahlen 0-6 wären somit bevorzugt.
Ich bin ein bisschen zu müde, um die Wahrscheinlichkeiten für diese Zahlen auszurechnen, will jemand? 

Zusammenfassend: <random> nimmt probabilistische Korrektheit über Laufzeit, C/rand() macht es umgekehrt.
(Ich kann mir durchaus vorstellen, dass bei frühen Computern die sich schnell ändernden Teile des CPU-Timers (die tiefen Bits) lieber als RNG-Source genommen wurden, was die Bevorzugung des Modulo teilweise erklären könnte. Aber das ist Spekulation)

@TE: Sorry, ist ein bisschen ausgeuftert 

Gruss
cwriter


----------

