it-swarm.com.de

Erweitern Sie einen zufälligen Bereich von 1–5 bis 1–7

Schreiben Sie bei einer Funktion, die eine zufällige ganze Zahl im Bereich von 1 bis 5 erzeugt, eine Funktion, die eine zufällige ganze Zahl im Bereich von 1 bis 7 erzeugt.

  1. Was ist eine einfache Lösung?
  2. Was ist eine effektive Lösung, um den Speicherbedarf zu reduzieren oder auf einer langsameren CPU zu laufen?
673
praveen

Dies entspricht der Lösung von Adam Rosenfield, ist jedoch für einige Leser etwas klarer. Es wird davon ausgegangen, dass Rand5 () eine Funktion ist, die eine statistisch zufällige Ganzzahl im Bereich von 1 bis einschließlich 5 zurückgibt.

int Rand7()
{
    int vals[5][5] = {
        { 1, 2, 3, 4, 5 },
        { 6, 7, 1, 2, 3 },
        { 4, 5, 6, 7, 1 },
        { 2, 3, 4, 5, 6 },
        { 7, 0, 0, 0, 0 }
    };

    int result = 0;
    while (result == 0)
    {
        int i = Rand5();
        int j = Rand5();
        result = vals[i-1][j-1];
    }
    return result;
}

Wie funktioniert es? Stellen Sie sich das so vor: Stellen Sie sich vor, Sie drucken dieses zweidimensionale Array auf Papier, befestigen es an einer Dartscheibe und werfen nach dem Zufallsprinzip Darts darauf. Wenn Sie einen Wert ungleich Null treffen, handelt es sich um einen statistisch zufälligen Wert zwischen 1 und 7, da eine gleiche Anzahl von Nicht-Null-Werten zur Auswahl steht. Wenn Sie eine Null treffen, werfen Sie einfach den Pfeil weiter, bis Sie eine Nicht-Null treffen. Das ist, was dieser Code tut: Die Indizes i und j wählen zufällig einen Ort auf der Dartscheibe, und wenn wir kein gutes Ergebnis erzielen, werfen wir Darts.

Wie Adam gesagt hat, kann dies im schlimmsten Fall für immer laufen, aber statistisch ist der schlimmste Fall niemals der Fall. :)

554
Rob McAfee

Es gibt keine (genau richtige) Lösung, die in einer konstanten Zeitspanne ausgeführt wird, da 1/7 eine unendliche Dezimalzahl in der Basis 5 ist.


int i;
do
{
  i = 5 * (Rand5() - 1) + Rand5();  // i is now uniformly random between 1 and 25
} while(i > 21);
// i is now uniformly random between 1 and 21
return i % 7 + 1;  // result is now uniformly random between 1 and 7

Dies hat eine erwartete Laufzeit von 25/21 = 1,19 Iterationen der Schleife, aber es gibt eine unendlich kleine Wahrscheinlichkeit, dass die Schleife für immer wiederholt wird.

339
Adam Rosenfield

Ich möchte zusätzlich zu meine erste Antwort eine weitere Antwort hinzufügen. Diese Antwort versucht, die Anzahl der Aufrufe von Rand5() pro Aufruf von Rand7() zu minimieren, um die Verwendung der Zufälligkeit zu maximieren. Das heißt, wenn Sie Zufälligkeit als wertvolle Ressource betrachten, möchten wir so viel wie möglich davon verwenden, ohne zufällige Bits wegzuwerfen. Diese Antwort hat auch einige Ähnlichkeiten mit der Logik in Iwans Antwort .

Die Entropie einer Zufallsvariablen ist eine genau definierte Größe. Für eine Zufallsvariable, die mit gleicher Wahrscheinlichkeit N Zustände annimmt (Gleichverteilung), ist die Entropie log2 N. Somit hat Rand5() ungefähr 2.32193 Entropiebits, und Rand7() hat ungefähr 2.80735 Entropiebits. Wenn wir die Zufälligkeit maximal nutzen möchten, müssen wir alle 2.32193 Entropiebits von jedem Aufruf von Rand5() verwenden und sie anwenden, um 2.80735 Entropiebits zu generieren, die für jeden Aufruf von Rand7() benötigt werden. Die grundlegende Grenze ist also, dass wir nichts Besseres tun können als log (7)/log (5) = 1.20906 Aufrufe von Rand5() pro Aufruf von Rand7().

Randnotizen: Alle Logarithmen in dieser Antwort sind Basis 2, sofern nicht anders angegeben. Es wird angenommen, dass Rand5() Zahlen im Bereich [0, 4] zurückgibt, und es wird angenommen, dass Rand7() Zahlen im Bereich [0, 6] zurückgibt. Das Einstellen der Bereiche auf [1, 5] bzw. [1, 7] ist trivial.

Wie machen wir das? Wir erzeugen eine unendlich genaue zufällige reelle Zahl zwischen 0 und 1 (tun Sie für den Moment so, als könnten wir tatsächlich eine unendlich genaue Zahl berechnen und speichern - wir werde das später beheben). Wir können eine solche Zahl erzeugen, indem wir ihre Ziffern in Basis 5 erzeugen: Wir wählen die Zufallszahl 0.a1a2a3..., wobei jede Ziffer ai wird durch einen Aufruf von Rand5() ausgewählt. Zum Beispiel, wenn unsere RNG ai = 1 für alle i, ignoriert dann die Tatsache, dass das nicht sehr zufällig ist, was der reellen Zahl 1/5 + 1/5 entsprechen würde2 + 1/53 + ... = 1/4 (Summe einer geometrischen Reihe).

Ok, also haben wir eine zufällige reelle Zahl zwischen 0 und 1 ausgewählt. Ich behaupte nun, dass eine solche Zufallszahl gleichmäßig verteilt ist. Intuitiv ist dies leicht zu verstehen, da jede Ziffer einheitlich ausgewählt wurde und die Zahl unendlich genau ist. Ein formaler Beweis dafür ist jedoch etwas komplizierter, da es sich jetzt um eine kontinuierliche Verteilung handelt, anstatt um eine diskrete Verteilung. Wir müssen also beweisen, dass die Wahrscheinlichkeit, dass unsere Zahl in einem Intervall liegt, [a, b] entspricht der Länge dieses Intervalls, b - a. Der Beweis bleibt als Übung für den Leser =).

Nachdem wir nun eine zufällige reelle Zahl aus dem Bereich [0, 1] ausgewählt haben, müssen wir sie in eine Reihe gleichmäßig zufälliger Zahlen im Bereich [0, 6] konvertieren, um die Ausgabe von Rand7() zu generieren. Wie machen wir das? Das Gegenteil von dem, was wir gerade getan haben - wir konvertieren es in eine unendlich genaue Dezimalstelle in Basis 7, und dann entspricht jede Ziffer der Basis 7 einer Ausgabe von Rand7().

Wenn unser Rand5() im Beispiel von früher einen unendlichen Strom von Einsen ergibt, ist unsere zufällige reelle Zahl 1/4. Wenn wir 1/4 in Basis 7 umwandeln, erhalten wir die unendliche Dezimalzahl 0,15151515 ..., sodass wir als Ausgabe 1, 5, 1, 5, 1, 5 usw. produzieren.

Okay, wir haben also die Hauptidee, aber wir haben noch zwei Probleme: Wir können eine unendlich genaue reelle Zahl nicht berechnen oder speichern. Wie gehen wir also nur mit einem begrenzten Teil davon um? Zweitens, wie konvertieren wir es tatsächlich zur Basis 7?

Eine Möglichkeit, eine Zahl zwischen 0 und 1 in Basis 7 umzuwandeln, ist wie folgt:

  1. Mit 7 multiplizieren
  2. Der integrale Bestandteil des Ergebnisses ist die nächste 7-stellige Basis
  3. Subtrahieren Sie den integralen Teil und lassen Sie nur den Bruchteil übrig
  4. Springe zu Schritt 1

Um das Problem der unendlichen Präzision zu lösen, berechnen wir ein Teilergebnis und speichern eine Obergrenze für das Ergebnis. Angenommen, wir haben Rand5() zweimal aufgerufen und es wurde beide Male 1 zurückgegeben. Die Zahl, die wir bisher generiert haben, ist 0,11 (Basis 5). Was auch immer der Rest der unendlichen Folge von Aufrufen von Rand5() erzeugt, die zufällige reelle Zahl, die wir erzeugen, wird niemals größer als 0,12 sein: Es ist immer wahr, dass 0,11 ≤ 0,11xyz ... <0,12.

Unter Verfolgung der bisherigen aktuellen Zahl und des Maximalwerts, den sie jemals annehmen könnte, konvertieren wir beide Zahlen in Basis 7. Wenn sie übereinstimmen die ersten k Ziffern, dann können wir die nächsten k Ziffern sicher ausgeben - unabhängig davon, was der unendliche Strom von Basis-5-Ziffern ist, beeinflussen sie niemals die nächsten k Ziffern der Basis 7 Darstellung!

Und das ist der Algorithmus - um die nächste Ausgabe von Rand7() zu generieren, generieren wir nur so viele Ziffern von Rand5(), wie wir benötigen, um den Wert der nächsten Ziffer bei der Konvertierung von mit Sicherheit zu kennen Die zufällige reelle Zahl zur Basis 7. Hier ist eine Implementierung von Python mit einem Test-Harness:

import random

Rand5_calls = 0
def Rand5():
    global Rand5_calls
    Rand5_calls += 1
    return random.randint(0, 4)

def Rand7_gen():
    state = 0
    pow5 = 1
    pow7 = 7
    while True:
        if state / pow5 == (state + pow7) / pow5:
            result = state / pow5
            state = (state - result * pow5) * 7
            pow7 *= 7
            yield result
        else:
            state = 5 * state + pow7 * Rand5()
            pow5 *= 5

if __== '__main__':
    r7 = Rand7_gen()
    N = 10000
    x = list(next(r7) for i in range(N))
    distr = [x.count(i) for i in range(7)]
    expmean = N / 7.0
    expstddev = math.sqrt(N * (1.0/7.0) * (6.0/7.0))

    print '%d TRIALS' % N
    print 'Expected mean: %.1f' % expmean
    print 'Expected standard deviation: %.1f' % expstddev
    print
    print 'DISTRIBUTION:'
    for i in range(7):
        print '%d: %d   (%+.3f stddevs)' % (i, distr[i], (distr[i] - expmean) / expstddev)
    print
    print 'Calls to Rand5: %d (average of %f per call to Rand7)' % (Rand5_calls, float(Rand5_calls) / N)

Beachten Sie, dass Rand7_gen() einen Generator zurückgibt, da dieser einen internen Status hat, der die Umwandlung der Zahl in Basis 7 beinhaltet. Das Testkabel ruft next(r7) 10000-mal auf, um 10000 Zufallszahlen zu erzeugen, und misst dann deren Verteilung. Es wird nur Ganzzahl-Mathematik verwendet, daher sind die Ergebnisse genau richtig.

Beachten Sie auch, dass die Zahlen hier sehr groß, sehr schnell werden. Potenzen von 5 und 7 wachsen schnell. Daher wird die Leistung nach der Erzeugung vieler Zufallszahlen aufgrund von Bignum-Arithmetik merklich beeinträchtigt. Aber denken Sie daran, mein Ziel war es, die Verwendung von Zufallsbits zu maximieren, nicht die Leistung zu maximieren (obwohl dies ein sekundäres Ziel ist).

In einem Durchlauf habe ich 12091 Aufrufe von Rand5() für 10000 Aufrufe von Rand7() getätigt und dabei das Minimum an log (7)/log (5) -Anrufen im Durchschnitt auf 4 signifikante Zahlen und das Ergebnis erreicht Ausgabe war einheitlich.

Um diesen Code in eine Sprache zu portieren, in der keine willkürlich großen Ganzzahlen integriert sind, müssen Sie die Werte von pow5 und pow7 auf den Maximalwert Ihres nativen Integraltyps begrenzen - Wenn sie zu groß werden, setzen Sie alles zurück und beginnen Sie von vorne. Dadurch wird die durchschnittliche Anzahl der Aufrufe von Rand5() pro Aufruf von Rand7() geringfügig erhöht, aber hoffentlich sollte sie selbst für 32- oder 64-Bit-Ganzzahlen nicht zu stark ansteigen.

153
Adam Rosenfield

(Ich habe gestohlen Adam Rosenfelds Antwort und habe es um 7% schneller laufen lassen.)

Angenommen, Rand5 () gibt einen Wert von {0,1,2,3,4} mit gleicher Verteilung zurück, und das Ziel ist die Ausgabe von {0,1,2,3,4,5,6} mit gleicher Verteilung.

int Rand7() {
  i = 5 * Rand5() + Rand5();
  max = 25;
  //i is uniform among {0 ... max-1}
  while(i < max%7) {
    //i is uniform among {0 ... (max%7 - 1)}
    i *= 5;
    i += Rand5(); //i is uniform {0 ... (((max%7)*5) - 1)}
    max %= 7;
    max *= 5; //once again, i is uniform among {0 ... max-1}
  }
  return(i%7);
}

Wir verfolgen den größten Wert, den die Schleife in der Variablen max machen kann. Wenn das Ergebnis bisher zwischen max% 7 und max-1 liegt, wird das Ergebnis in diesem Bereich gleichmäßig verteilt. Wenn nicht, verwenden wir den Rest, der zufällig zwischen 0 und max% 7-1 liegt, und einen weiteren Aufruf an Rand (), um eine neue Nummer und eine neue max zu erstellen. Dann fangen wir wieder an.

Edit: Erwarte, wie oft Rand5 () aufgerufen wird, ist x in dieser Gleichung:

x =  2     * 21/25
   + 3     *  4/25 * 14/20
   + 4     *  4/25 *  6/20 * 28/30
   + 5     *  4/25 *  6/20 *  2/30 * 7/10
   + 6     *  4/25 *  6/20 *  2/30 * 3/10 * 14/15
   + (6+x) *  4/25 *  6/20 *  2/30 * 3/10 *  1/15
x = about 2.21 calls to Rand5()
36
Eyal

Algorithmus:

7 kann in einer Folge von 3 Bits dargestellt werden

Verwenden Sie Rand (5), um jedes Bit zufällig mit 0 oder 1 zu füllen.
Zum Beispiel: Rand (5) und anrufen 

wenn das Ergebnis 1 oder 2 ist, füllen Sie das Bit mit 0
Wenn das Ergebnis 4 oder 5 ist, füllen Sie das Bit mit 1
Wenn das Ergebnis 3 ist, dann ignorieren Sie es und wiederholen Sie es (Ablehnung). 

Auf diese Weise können wir 3 Bits zufällig mit 0/1 füllen und somit eine Zahl von 1-7 erhalten.

EDIT: Dies scheint die einfachste und effizienteste Antwort zu sein, daher gibt es hier einen Code dafür:

public static int random_7() {
    int returnValue = 0;
    while (returnValue == 0) {
        for (int i = 1; i <= 3; i++) {
            returnValue = (returnValue << 1) + random_5_output_2();
        }
    }
    return returnValue;
}

private static int random_5_output_2() {
    while (true) {
        int flip = random_5();

        if (flip < 3) {
            return 0;
        }
        else if (flip > 3) {
            return 1;
        }
    }
}
27
Anand
int randbit( void )
{
    while( 1 )
    {
        int r = Rand5();
        if( r <= 4 ) return(r & 1);
    }
}

int randint( int nbits )
{
    int result = 0;
    while( nbits-- )
    {
        result = (result<<1) | randbit();
    }
    return( result );
}

int Rand7( void )
{
    while( 1 )
    {
        int r = randint( 3 ) + 1;
        if( r <= 7 ) return( r );
    }
}
19
Mike F
int ans = 0;
while (ans == 0) 
{
     for (int i=0; i<3; i++) 
     {
          while ((r = Rand5()) == 3){};
          ans += (r < 3) >> i
     }
}
15
Nescio
Rand7() = (Rand5()+Rand5()+Rand5()+Rand5()+Rand5()+Rand5()+Rand5())%7+1

Edit: Das funktioniert nicht ganz. Es ist um 2 Teile in 1000 (von einem perfekten Rand5 ausgegangen). Die Eimer erhalten:

value   Count  Error%
1       11158  -0.0035
2       11144  -0.0214
3       11144  -0.0214
4       11158  -0.0035
5       11172  +0.0144
6       11177  +0.0208
7       11172  +0.0144

Durch Umschalten auf eine Summe von

n   Error%
10  +/- 1e-3,
12  +/- 1e-4,
14  +/- 1e-5,
16  +/- 1e-6,
...
28  +/- 3e-11

scheint für jede hinzugefügte 2 eine Größenordnung zu gewinnen

Übrigens: Die obige Fehlertabelle wurde nicht durch Stichproben erstellt, sondern durch die folgende Wiederholungsbeziehung:

p[x,n] ist die Anzahl, wie output=x bei n-Aufrufen von Rand5 vorkommen kann.

  p[1,1] ... p[5,1] = 1
  p[6,1] ... p[7,1] = 0

  p[1,n] = p[7,n-1] + p[6,n-1] + p[5,n-1] + p[4,n-1] + p[3,n-1]
  p[2,n] = p[1,n-1] + p[7,n-1] + p[6,n-1] + p[5,n-1] + p[4,n-1]
  p[3,n] = p[2,n-1] + p[1,n-1] + p[7,n-1] + p[6,n-1] + p[5,n-1]
  p[4,n] = p[3,n-1] + p[2,n-1] + p[1,n-1] + p[7,n-1] + p[6,n-1]
  p[5,n] = p[4,n-1] + p[3,n-1] + p[2,n-1] + p[1,n-1] + p[7,n-1]
  p[6,n] = p[5,n-1] + p[4,n-1] + p[3,n-1] + p[2,n-1] + p[1,n-1]
  p[7,n] = p[6,n-1] + p[5,n-1] + p[4,n-1] + p[3,n-1] + p[2,n-1]
15
BCS

Das Folgende erzeugt eine Gleichverteilung auf {1, 2, 3, 4, 5, 6, 7} unter Verwendung eines Zufallsgenerators, der eine Gleichverteilung auf {1, 2, 3, 4, 5} erzeugt. Der Code ist unordentlich, aber die Logik ist klar.

public static int random_7(Random rg) {
    int returnValue = 0;
    while (returnValue == 0) {
        for (int i = 1; i <= 3; i++) {
            returnValue = (returnValue << 1) + SimulateFairCoin(rg);
        }
    }
    return returnValue;
}

private static int SimulateFairCoin(Random rg) {
    while (true) {
        int flipOne = random_5_mod_2(rg);
        int flipTwo = random_5_mod_2(rg);

        if (flipOne == 0 && flipTwo == 1) {
            return 0;
        }
        else if (flipOne == 1 && flipTwo == 0) {
            return 1;
        }
    }
}

private static int random_5_mod_2(Random rg) {
    return random_5(rg) % 2;
}

private static int random_5(Random rg) {
    return rg.Next(5) + 1;
}    
13
jason

Wenn wir die zusätzliche Einschränkung betrachten, zu versuchen, die effizienteste Antwort zu geben, d. H. Eine, die einen Eingangsstrom I von gleichmäßig verteilten Ganzzahlen der Länge m von 1-5 angibt, gibt einen Strom O von gleichverteilten Ganzzahlen von 1 bis 7 aus längste Länge relativ zu m, beispielsweise L(m)

Der einfachste Weg, dies zu analysieren, besteht darin, die Ströme I und O als 5-stellige bzw. 7-arige Zahlen zu behandeln. Dies wird durch die Idee der Hauptantwort erreicht, den Stream a1, a2, a3,... -> a1+5*a2+5^2*a3+.. und in ähnlicher Weise für den Stream O zu verwenden.

Dann nehmen wir einen Abschnitt des Eingabestroms der Länge m choose n s.t. 5^m-7^n=c, wobei c>0 und so klein wie möglich ist. Dann gibt es eine einheitliche Zuordnung vom Eingangsstrom der Länge m zu Ganzzahlen von 1 bis 5^m und eine weitere einheitliche Karte von Ganzzahlen von 1 bis 7^n zum Ausgangsstrom der Länge n, wo wir möglicherweise einige Fälle aus dem Eingangsstrom verlieren müssen Die zugeordnete Ganzzahl überschreitet 7^n.

Dies gibt also einen Wert für L(m) um m (log5/log7), der ungefähr .82m ist.

Die Schwierigkeit bei der obigen Analyse ist die Gleichung 5^m-7^n=c, die nicht genau zu lösen ist, und der Fall, bei dem der einheitliche Wert von 1 bis 5^m7^n übersteigt und die Effizienz verloren geht. 

Die Frage ist, wie nahe der bestmögliche Wert von m (log5/log7) erreicht werden kann. Wenn sich diese Zahl beispielsweise einer ganzen Zahl annähert, können wir einen Weg finden, um genau diese ganzzahlige Anzahl von Ausgabewerten zu erreichen? 

Wenn 5^m-7^n=c aus dem Eingabestrom erzeugt wird, erzeugen wir effektiv eine einheitliche Zufallszahl von 0 bis (5^m)-1 und verwenden keine höheren Werte als 7^n. Diese Werte können jedoch gerettet und erneut verwendet werden. Sie erzeugen effektiv eine einheitliche Zahlenfolge von 1 bis 5^m-7^n. Wir können dann versuchen, diese zu verwenden und in 7-ary Zahlen umzuwandeln, damit wir mehr Ausgabewerte erzeugen können. 

Wenn wir T7(X) als durchschnittliche Länge der Ausgangssequenz von random(1-7)-Ganzzahlen angeben, die von einer einheitlichen Eingabe der Größe X abgeleitet werden, und unter der Annahme, dass 5^m=7^n0+7^n1+7^n2+...+7^nr+s, s<7.

Dann T7(5^m)=n0x7^n0/5^m + ((5^m-7^n0)/5^m) T7(5^m-7^n0), da wir eine Länge ohne Sequenz mit einer Wahrscheinlichkeit von 7 ^ n0/5 ^ m mit einem Rest der Länge 5^m-7^n0 mit einer Wahrscheinlichkeit (5^m-7^n0)/5^m) haben.

Wenn wir einfach weiter substituieren, erhalten wir:

T7(5^m) = n0x7^n0/5^m + n1x7^n1/5^m + ... + nrx7^nr/5^m  = (n0x7^n0 + n1x7^n1 + ... + nrx7^nr)/5^m

Daher

L(m)=T7(5^m)=(n0x7^n0 + n1x7^n1 + ... + nrx7^nr)/(7^n0+7^n1+7^n2+...+7^nr+s)

Eine andere Möglichkeit, dies zu sagen, ist:

If 5^m has 7-ary representation `a0+a1*7 + a2*7^2 + a3*7^3+...+ar*7^r
Then L(m) = (a1*7 + 2a2*7^2 + 3a3*7^3+...+rar*7^r)/(a0+a1*7 + a2*7^2 + a3*7^3+...+ar*7^r)

Der bestmögliche Fall ist mein ursprünglicher Fall, bei dem 5^m=7^n+s und s<7.

Dann T7(5^m) = nx(7^n)/(7^n+s) = n+o(1) = m (Log5/Log7)+o(1) wie zuvor.

Der schlimmste Fall liegt vor, wenn wir nur k und s.t 5 ^ m = kx7 + s finden können.

Then T7(5^m) = 1x(k.7)/(k.7+s) = 1+o(1)

Andere Fälle liegen irgendwo dazwischen. Es wäre interessant zu sehen, wie gut wir für sehr große m arbeiten können, d. H. Wie gut wir den Fehlerausdruck erhalten können:

T7(5^m) = m (Log5/Log7)+e(m)

Es scheint unmöglich zu sein, e(m) = o(1) im Allgemeinen zu erreichen, aber hoffentlich können wir e(m)=o(m) beweisen.

Das Ganze beruht dann auf der Verteilung der 7-stelligen Ziffern von 5^m für verschiedene Werte von m.

Ich bin sicher, dass es eine Menge Theorie gibt, die das abdeckt. Vielleicht schaue ich irgendwann darauf zurück. 

12
Ivan

Dürfen hier Hausaufgabenprobleme?

Diese Funktion führt eine einfache "Basis 5" -Methode aus, um eine Zahl zwischen 0 und 6 zu generieren.

function rnd7() {
    do {
        r1 = rnd5() - 1;
        do {
            r2=rnd5() - 1;
        } while (r2 > 1);
        result = r2 * 5 + r1;
    } while (result > 6);
    return result + 1;
}
11
Will Hartung

Warum machst du es nicht einfach?

int random7() {
  return random5() + (random5() % 3);
}

Die Wahrscheinlichkeit, 1 und 7 in dieser Lösung zu erhalten, ist aufgrund des Modulo geringer. Wenn Sie nur eine schnelle und lesbare Lösung wünschen, ist dies der richtige Weg.

10
Ante

Hier ist eine funktionierende Python-Implementierung von Adams Antwort .

import random

def Rand5():
    return random.randint(1, 5)

def Rand7():
    while True:
        r = 5 * (Rand5() - 1) + Rand5()
        #r is now uniformly random between 1 and 25
        if (r <= 21):
            break
    #result is now uniformly random between 1 and 7
    return r % 7 + 1

Ich mag es, Algorithmen zu werfen, die ich mir in Python anschaue, damit ich mit ihnen herumspielen kann. Ich dachte, ich würde es hier posten, in der Hoffnung, dass es für jemanden nützlich ist.

10
James McMahon

Die Prämisse hinter Adam Rosenfields richtiger Antwort lautet:

  • x = 5 ^ n (in seinem Fall: n = 2)
  • n Rand5-Anrufe manipulieren, um eine Zahl y innerhalb des Bereichs [1, x] zu erhalten
  • z = ((int) (x/7)) * 7
  • wenn y> z, versuchen Sie es erneut. Andernfalls geben Sie y% 7 + 1 zurück

Wenn n gleich 2 ist, haben Sie 4 Auswurfmöglichkeiten: y = {22, 23, 24, 25}. Wenn Sie n gleich 6 verwenden, haben Sie nur einen Wurf: y = {15625}.

5 ^ 6 = 15625
7 * 2232 = 15624

Sie rufen mehr Rand5 an. Sie haben jedoch eine viel geringere Chance, einen Wegwerfwert (oder eine Endlosschleife) zu erhalten. Wenn es einen Weg gibt, keinen möglichen Einwegwert für y zu erhalten, habe ich ihn noch nicht gefunden.

8
Dinah

Hier ist meine Antwort:

static struct Rand_buffer {
  unsigned v, count;
} buf2, buf3;

void Push (struct Rand_buffer *buf, unsigned n, unsigned v)
{
  buf->v = buf->v * n + v;
  ++buf->count;
}

#define Push(n, v)  Push (&buf##n, n, v)

int Rand16 (void)
{
  int v = buf2.v & 0xf;
  buf2.v >>= 4;
  buf2.count -= 4;
  return v;
}

int Rand9 (void)
{
  int v = buf3.v % 9;
  buf3.v /= 9;
  buf3.count -= 2;
  return v;
}

int Rand7 (void)
{
  if (buf3.count >= 2) {
    int v = Rand9 ();

    if (v < 7)
      return v % 7 + 1;

    Push (2, v - 7);
  }

  for (;;) {
    if (buf2.count >= 4) {
      int v = Rand16 ();

      if (v < 14) {
        Push (2, v / 7);
        return v % 7 + 1;
      }

      Push (2, v - 14);
    }

    // Get a number between 0 & 25
    int v = 5 * (Rand5 () - 1) + Rand5 () - 1;

    if (v < 21) {
      Push (3, v / 7);
      return v % 7 + 1;
    }

    v -= 21;
    Push (2, v & 1);
    Push (2, v >> 1);
  }
}

Es ist etwas komplizierter als andere, aber ich glaube, es minimiert die Aufrufe von Rand5. Wie bei anderen Lösungen besteht eine geringe Wahrscheinlichkeit, dass es eine lange Schleife durchläuft.

8
Chris Suter

Angenommen, Rand (n) bedeutet hier "zufällige ganze Zahl in einer gleichmäßigen Verteilung von 0 bis n-1", hier ein Codebeispiel, das Pythons Randint verwendet, was diesen Effekt hat. Es verwendet nur randint (5) und Konstanten, um den Effekt von randint (7) zu erzeugen. Eigentlich ein bisschen dumm

from random import randint
sum = 7
while sum >= 7:
    first = randint(0,5)   
    toadd = 9999
    while toadd>1:
        toadd = randint(0,5)
    if toadd:
        sum = first+5
    else:
        sum = first

assert 7>sum>=0 
print sum
8
Joshua Fox
int Rand7() {
    int value = Rand5()
              + Rand5() * 2
              + Rand5() * 3
              + Rand5() * 4
              + Rand5() * 5
              + Rand5() * 6;
    return value%7;
}

Im Gegensatz zur gewählten Lösung läuft der Algorithmus in konstanter Zeit. Es werden jedoch 2 mehr Aufrufe an Rand5 als die durchschnittliche Laufzeit der ausgewählten Lösung ausgeführt.

Beachten Sie, dass dieser Generator nicht perfekt ist (die Zahl 0 hat eine Chance von 0,0064% mehr als jede andere Zahl), aber für die meisten praktischen Zwecke überwiegt die Garantie einer konstanten Zeit diese Ungenauigkeit.

Erklärung

Diese Lösung ergibt sich aus der Tatsache, dass die Zahl 15.624 durch 7 teilbar ist. Wenn wir also zufällig und gleichmäßig Zahlen von 0 bis 15.624 generieren und dann Mod 7 nehmen können, können wir einen nahezu gleichförmigen Rand7-Generator erhalten. Zahlen von 0 bis 15.624 können einheitlich erzeugt werden, indem Rand5 sechsmal gewalzt und zur Bildung der Ziffern einer Basis-5-Nummer wie folgt verwendet wird:

Rand5 * 5^5 + Rand5 * 5^4 + Rand5 * 5^3 + Rand5 * 5^2 + Rand5 * 5 + Rand5

Die Eigenschaften von Mod 7 erlauben uns jedoch, die Gleichung etwas zu vereinfachen:

5^5 = 3 mod 7
5^4 = 2 mod 7
5^3 = 6 mod 7
5^2 = 4 mod 7
5^1 = 5 mod 7

So

Rand5 * 5^5 + Rand5 * 5^4 + Rand5 * 5^3 + Rand5 * 5^2 + Rand5 * 5 + Rand5

wird

Rand5 * 3 + Rand5 * 2 + Rand5 * 6 + Rand5 * 4 + Rand5 * 5 + Rand5

Theorie

Die Zahl 15.624 wurde nicht zufällig gewählt, kann aber mit Hilfe des kleinen Satzes von Fermat entdeckt werden, der besagt, dass dann, wenn p eine Primzahl ist

a^(p-1) = 1 mod p

Das gibt uns also

(5^6)-1 = 0 mod 7

(5 ^ 6) -1 ist gleich

4 * 5^5 + 4 * 5^4 + 4 * 5^3 + 4 * 5^2 + 4 * 5 + 4

Dies ist eine Zahl in der Basis-5-Form, und somit können wir sehen, dass diese Methode verwendet werden kann, um von einem beliebigen Zufallszahlengenerator zu einem beliebigen anderen Zufallszahlengenerator zu gelangen. Bei Verwendung des Exponenten p-1 wird jedoch immer eine kleine Abweichung von 0 eingeführt.

7
Thirlan

Einfach und effizient:

int Rand7 ( void )
{
    return 4; // this number has been calculated using
              // Rand5() and is in the range 1..7
}

(Inspiriert von Was ist dein Lieblings-Cartoon-Programmierer? ).

7
chiccodoro

Solange keine sieben Möglichkeiten zur Auswahl stehen, zeichnen Sie eine weitere Zufallszahl, die die Anzahl der Möglichkeiten mit fünf multipliziert. In Perl:

$num = 0;
$possibilities = 1;

sub Rand7
{
  while( $possibilities < 7 )
  {
    $num = $num * 5 + int(Rand(5));
    $possibilities *= 5;
  }
  my $result = $num % 7;
  $num = int( $num / 7 );
  $possibilities /= 7;
  return $result;
}
6
bmcnett

Ich mag keine Bereiche ab 1, also fange ich bei 0 an :-)

unsigned Rand5()
{
    return Rand() % 5;
}

unsigned Rand7()
{
    int r;

    do
    {
        r =         Rand5();
        r = r * 5 + Rand5();
        r = r * 5 + Rand5();
        r = r * 5 + Rand5();
        r = r * 5 + Rand5();
        r = r * 5 + Rand5();
    } while (r > 15623);

    return r / 2232;
}
6
fredoverflow

Los geht's, gleichmäßige Verteilung und null Rand5-Anrufe.

def Rand7:
    seed += 1
    if seed >= 7:
        seed = 0
    yield seed

Das Saatgut muss vorher gesetzt werden.

5
Kugel

Ich weiß, dass es beantwortet wurde, aber scheint das zu funktionieren, aber ich kann Ihnen nicht sagen, ob es eine Befangenheit hat. Mein "Testen" legt nahe, dass es zumindest vernünftig ist.

Vielleicht wäre Adam Rosenfield so nett zu kommentieren?

Meine (naive?) Idee ist folgende:

Sammle Rand5-Werte, bis genügend Randbits vorhanden sind, um Rand7 zu erstellen. Dies dauert höchstens 2 Rand5. Um die Rand7-Nummer zu erhalten, verwende ich den akkumulierten Wert mod 7.

Um zu vermeiden, dass der Akku überläuft, und da der Akku Mod 7 ist, nehme ich den Mod 7 des Akkus:

(5a + Rand5) % 7 = (k*7 + (5a%7) + Rand5) % 7 = ( (5a%7) + Rand5) % 7

Die Funktion Rand7 () folgt:

(Ich lasse den Bereich von Rand5 0-4 sein und Rand7 ist ebenfalls 0-6.)

int Rand7(){
  static int    a=0;
  static int    e=0;
  int       r;
  a = a * 5 + Rand5();
  e = e + 5;        // added 5/7ths of a Rand7 number
  if ( e<7 ){
    a = a * 5 + Rand5();
    e = e + 5;  // another 5/7ths
  }
  r = a % 7;
  e = e - 7;        // removed a Rand7 number
  a = a % 7;
  return r;
}

Bearbeiten: Hinzugefügte Ergebnisse für 100 Millionen Versuche.

'Real' Rand-Funktionen Mod 5 oder 7

Rand5: avg = 1.999802 0: 20003944 1: 19999889 2: 20003690 3: 19996938 4: 19995539.__ Rand7: av = 3.000111 0: 14282851 1: 14284579 3: 14288546 4: 14282 828 4: 14282388 5: 142828388

Mein Rand7

Durchschnittlich sieht ok aus und Zahlenverteilungen sehen auch ok aus.

randt: avg = 3.000080 0: 14288793 1: 14280135 2: 14287848 3: 14285277 4: 14286341 5: 14278663 6: 14292943

5
philcolbourn

Hier ist eine Lösung, die vollständig in ganze Zahlen passt und innerhalb von etwa 4% des Optimums liegt (d. H. 1,26 Zufallszahlen in {0..4} für jede in {0..6} verwendet). Der Code ist in Scala, aber die Mathematik sollte in jeder Sprache einigermaßen klar sein: Sie nutzen die Tatsache, dass 7 ^ 9 + 7 ^ 8 sehr nahe an 5 ^ 11 liegt. Sie wählen also eine 11-stellige Nummer in Basis 5 aus und interpretieren sie dann als 9-stellige Nummer in Basis 7 (wenn sie sich in Reichweite befindet (9 Basis-7-Nummern angeben)) oder als achtstellige Zahl, wenn sie über der 9-stelligen Nummer liegt, usw .:

abstract class RNG {
  def apply(): Int
}

class Random5 extends RNG {
  val rng = new scala.util.Random
  var count = 0
  def apply() = { count += 1 ; rng.nextInt(5) }
}

class FiveSevener(five: RNG) {
  val sevens = new Array[Int](9)
  var nsevens = 0
  val to9 = 40353607;
  val to8 = 5764801;
  val to7 = 823543;
  def loadSevens(value: Int, count: Int) {
    nsevens = 0;
    var remaining = value;
    while (nsevens < count) {
      sevens(nsevens) = remaining % 7
      remaining /= 7
      nsevens += 1
    }
  }
  def loadSevens {
    var fivepow11 = 0;
    var i=0
    while (i<11) { i+=1 ; fivepow11 = five() + fivepow11*5 }
    if (fivepow11 < to9) { loadSevens(fivepow11 , 9) ; return }
    fivepow11 -= to9
    if (fivepow11 < to8) { loadSevens(fivepow11 , 8) ; return }
    fivepow11 -= to8
    if (fivepow11 < 3*to7) loadSevens(fivepow11 % to7 , 7)
    else loadSevens
  }
  def apply() = {
    if (nsevens==0) loadSevens
    nsevens -= 1
    sevens(nsevens)
  }
}

Wenn Sie einen Test in den Interpreter einfügen (tatsächlich REPL), erhalten Sie:

scala> val five = new Random5
five: Random5 = [email protected]

scala> val seven = new FiveSevener(five)
seven: FiveSevener = [email protected]

scala> val counts = new Array[Int](7)
counts: Array[Int] = Array(0, 0, 0, 0, 0, 0, 0)

scala> var i=0 ; while (i < 100000000) { counts( seven() ) += 1 ; i += 1 }
i: Int = 100000000

scala> counts
res0: Array[Int] = Array(14280662, 14293012, 14281286, 14284836, 14287188,
14289332, 14283684)

scala> five.count
res1: Int = 125902876

Die Verteilung ist schön und flach (innerhalb von etwa 10.000 von 1/7 von 10 ^ 8 in jedem Behälter, wie von einer ungefähr-Gaußschen Verteilung erwartet).

4
Rex Kerr

Es gibt elegante Algorithmen, die oben zitiert wurden, aber es gibt eine Möglichkeit, sich ihr zu nähern, auch wenn es sich um einen Kreisverkehr handeln könnte. Ich gehe davon aus, dass Werte von 0 generiert werden.

R2 = Zufallszahlengenerator mit Werten unter 2 (Abtastraum = {0, 1})
R8 = Zufallszahlengenerator mit Werten unter 8 (Abtastraum = {0, 1, 2, 3, 4, 5, 6, 7})

Um R8 aus R2 zu generieren, führen Sie R2 dreimal aus und verwenden das kombinierte Ergebnis aller 3 Läufe als Binärzahl mit 3 Ziffern. Hier ist der Wertebereich, wenn R2 dreimal ausgeführt wird:

0 0 0 -> 0
.
.
.__ 1 1 1 -> 7

Um nun R7 aus R8 zu generieren, führen wir einfach R7 erneut aus, wenn 7 zurückgegeben wird:

int R7() {
  do {
    x = R8();
  } while (x > 6)
  return x;
}

Die Lösung des Kreisverkehrs besteht darin, R2 aus R5 zu generieren (genau wie R7 aus R8), dann aus R8 aus R2 und dann aus R8 aus R7.

4
Ashwin

Wenn Sie eine rollende Summe verwenden, können Sie beides

  • eine gleichmäßige Verteilung aufrechterhalten; und
  • muss kein Element in der zufälligen Reihenfolge opfern.

Diese beiden Probleme sind ein Problem bei den vereinfachten Lösungen vom Typ Rand(5)+Rand(5).... Der folgende Python-Code zeigt, wie er implementiert wird (das meiste davon ist der Nachweis der Verteilung).

import random
x = []
for i in range (0,7):
    x.append (0)
t = 0
tt = 0
for i in range (0,700000):
    ########################################
    #####            qq.py             #####
    r = int (random.random () * 5)
    t = (t + r) % 7
    ########################################
    #####       qq_notsogood.py        #####
    #r = 20
    #while r > 6:
        #r =     int (random.random () * 5)
        #r = r + int (random.random () * 5)
    #t = r
    ########################################
    x[t] = x[t] + 1
    tt = tt + 1
high = x[0]
low = x[0]
for i in range (0,7):
    print "%d: %7d %.5f" % (i, x[i], 100.0 * x[i] / tt)
    if x[i] < low:
        low = x[i]
    if x[i] > high:
        high = x[i]
diff = high - low
print "Variation = %d (%.5f%%)" % (diff, 100.0 * diff / tt)

Und diese Ausgabe zeigt die Ergebnisse:

pax$ python qq.py
0:   99908 14.27257
1:  100029 14.28986
2:  100327 14.33243
3:  100395 14.34214
4:   99104 14.15771
5:   99829 14.26129
6:  100408 14.34400
Variation = 1304 (0.18629%)

pax$ python qq.py
0:   99547 14.22100
1:  100229 14.31843
2:  100078 14.29686
3:   99451 14.20729
4:  100284 14.32629
5:  100038 14.29114
6:  100373 14.33900
Variation = 922 (0.13171%)

pax$ python qq.py
0:  100481 14.35443
1:   99188 14.16971
2:  100284 14.32629
3:  100222 14.31743
4:   99960 14.28000
5:   99426 14.20371
6:  100439 14.34843
Variation = 1293 (0.18471%)

Eine vereinfachte Rand(5)+Rand(5), die die Fälle ignoriert, in denen dies mehr als 6 ergibt, hat eine typische Abweichung von 18% 100-mal der oben gezeigten Methode:

pax$ python qq_notsogood.py
0:   31756 4.53657
1:   63304 9.04343
2:   95507 13.64386
3:  127825 18.26071
4:  158851 22.69300
5:  127567 18.22386
6:   95190 13.59857
Variation = 127095 (18.15643%)

pax$ python qq_notsogood.py
0:   31792 4.54171
1:   63637 9.09100
2:   95641 13.66300
3:  127627 18.23243
4:  158751 22.67871
5:  126782 18.11171
6:   95770 13.68143
Variation = 126959 (18.13700%)

pax$ python qq_notsogood.py
0:   31955 4.56500
1:   63485 9.06929
2:   94849 13.54986
3:  127737 18.24814
4:  159687 22.81243
5:  127391 18.19871
6:   94896 13.55657
Variation = 127732 (18.24743%)

Und auf den Rat von Nixuz habe ich das Skript bereinigt, sodass Sie einfach den Code Rand7... extrahieren und verwenden können:

import random

# Rand5() returns 0 through 4 inclusive.

def Rand5():
    return int (random.random () * 5)

# Rand7() generator returns 0 through 6 inclusive (using Rand5()).

def Rand7():
    Rand7ret = 0
    while True:
        Rand7ret = (Rand7ret + Rand5()) % 7
        yield Rand7ret

# Number of test runs.

count = 700000

# Work out distribution.

distrib = [0,0,0,0,0,0,0]
rgen =Rand7()
for i in range (0,count):
    r = rgen.next()
    distrib[r] = distrib[r] + 1

# Print distributions and calculate variation.

high = distrib[0]
low = distrib[0]
for i in range (0,7):
    print "%d: %7d %.5f" % (i, distrib[i], 100.0 * distrib[i] / count)
    if distrib[i] < low:
        low = distrib[i]
    if distrib[i] > high:
        high = distrib[i]
diff = high - low
print "Variation = %d (%.5f%%)" % (diff, 100.0 * diff / count)
3
paxdiablo

in php

function Rand1to7() {
    do {
        $output_value = 0;
        for ($i = 0; $i < 28; $i++) {
            $output_value += Rand1to5();
        }
    while ($output_value != 140);
    $output_value -= 12;
    return floor($output_value / 16);
}

schleifen, um eine Zufallszahl zwischen 16 und 127 zu erzeugen, durch 16 dividieren, um einen Float zwischen 1 und 7.9375 zu erstellen, dann abrunden, um ein Int zwischen 1 und 7 zu erhalten. Wenn ich mich nicht irre, besteht eine Chance von 16/112 eines der 7 Ergebnisse.

3
dqhendricks

Diese Antwort ist eher ein Experiment, um mit der Rand5-Funktion die größtmögliche Entropie zu erhalten. Es ist daher etwas unklar und fast sicher viel langsamer als bei anderen Implementierungen.

Angenommen, die Gleichverteilung von 0-4 und die daraus resultierende Gleichverteilung von 0-6:

public class SevenFromFive
{
  public SevenFromFive()
  {
    // this outputs a uniform ditribution but for some reason including it 
    // screws up the output distribution
    // open question Why?
    this.fifth = new ProbabilityCondensor(5, b => {});
    this.eigth = new ProbabilityCondensor(8, AddEntropy);
  } 

  private static Random r = new Random();
  private static uint Rand5()
  {
    return (uint)r.Next(0,5);
  }

  private class ProbabilityCondensor
  {
    private readonly int samples;
    private int counter;
    private int store;
    private readonly Action<bool> output;

    public ProbabilityCondensor(int chanceOfTrueReciprocal,
      Action<bool> output)
    {
      this.output = output;
      this.samples = chanceOfTrueReciprocal - 1;  
    }

    public void Add(bool bit)
    {
      this.counter++;
      if (bit)
        this.store++;   
      if (counter == samples)
      {
        bool? e;
        if (store == 0)
          e = false;
        else if (store == 1)
          e = true;
        else
          e = null;// discard for now       
        counter = 0;
        store = 0;
        if (e.HasValue)
          output(e.Value);
      }
    }
  }

  ulong buffer = 0;
  const ulong Mask = 7UL;
  int bitsAvail = 0;
  private readonly ProbabilityCondensor fifth;
  private readonly ProbabilityCondensor eigth;

  private void AddEntropy(bool bit)
  {
    buffer <<= 1;
    if (bit)
      buffer |= 1;      
    bitsAvail++;
  }

  private void AddTwoBitsEntropy(uint u)
  {
    buffer <<= 2;
    buffer |= (u & 3UL);    
    bitsAvail += 2;
  }

  public uint Rand7()
  {
    uint selection;   
    do
    {
      while (bitsAvail < 3)
      {
        var x = Rand5();
        if (x < 4)
        {
          // put the two low order bits straight in
          AddTwoBitsEntropy(x);
          fifth.Add(false);
        }
        else
        { 
          fifth.Add(true);
        }
      }
      // read 3 bits
      selection = (uint)((buffer & Mask));
      bitsAvail -= 3;     
      buffer >>= 3;
      if (selection == 7)
        eigth.Add(true);
      else
        eigth.Add(false);
    }
    while (selection == 7);   
    return selection;
  }
}

Die Anzahl der Bits, die pro Aufruf von Rand5 zum Puffer hinzugefügt werden, beträgt derzeit 4/5 * 2, also 1,6 . Wenn der Wahrscheinlichkeitswert von 1/5 enthalten ist, steigt der Wert um 0,05, also 1,65 musste das deaktivieren.

Vom Aufruf an Rand7 verbrauchte Bits = 3 + 1/8 * (3 + 1/8 * (3 + 1/8 * (...
Dies ist 3 + 3/8 + 3/64 + 3/512 ... also ungefähr 3.42

Durch das Extrahieren von Informationen aus den Siebenen erhalte ich 1/8 * 1/7 Bits pro Anruf, also etwa 0,018

Dies ergibt einen Netto-Verbrauch von 3,4 Bits pro Anruf. Dies bedeutet, dass das Verhältnis 2,125 Anrufe zu Rand5 für jeden Rand7 beträgt. Das Optimum sollte 2.1 sein.

Ich würde mir vorstellen, dass dieser Ansatz signifikanter langsamer ist als viele der anderen hier, es sei denn, die Kosten für den Aufruf von Rand5 sind extrem teuer (sagen wir, eine externe Entropiequelle anzurufen).

3
ShuggyCoUk
extern int r5();

int r7() {
    return ((r5() & 0x01) << 2 ) | ((r5() & 0x01) << 1 ) | (r5() & 0x01);
}
3
maxchengcn
Rand25() =5*(Rand5()-1) + Rand5()

Rand7() { 
   while(true) {
       int r = Rand25();
       if (r < 21) return r%3;         
   }
}

Warum dies funktioniert: Die Wahrscheinlichkeit, dass die Schleife für immer ausgeführt wird, ist 0.

2
ekr

Die Funktion, die Sie brauchen, ist Rand1_7 () . Ich habe Rand1_5 () geschrieben, damit Sie es testen und plotten können.

import numpy
def Rand1_5():
    return numpy.random.randint(5)+1

def Rand1_7():
    q = 0
    for i in xrange(7):  q+= Rand1_5()
    return q%7 + 1
2
Andrea Ambu

skalieren Sie einfach Ihre Ausgabe von Ihrer ersten Funktion

0) you have a number in range 1-5
1) subtract 1 to make it in range 0-4
2) multiply by (7-1)/(5-1) to make it in range 0-6
3) add 1 to increment the range: Now your result is in between 1-7
2
cartonn

Für die Werte 0-7 haben Sie Folgendes:

0 000
1 001
2 010
3 011
4 100
5 101
6 110
7 111

Von bitweise von links nach rechts hat Rand5 () p(1) = {2/5, 2/5, 3/5}. Wenn wir also diese Wahrscheinlichkeitsverteilungen (~ Rand5 ()) ergänzen, sollten wir diese verwenden können, um unsere Zahl zu erzeugen. Ich werde später versuchen, mich mit einer Lösung zu melden. Hat jemand irgendwelche Gedanken?

R

2
Rob Leclerc
int getOneToSeven(){
    int added = 0;
    for(int i = 1; i<=7; i++){
        added += getOneToFive();
    }
    return (added)%7+1;
}
2
pas1311

Wir verwenden hier die Konvention Rand(n) -> [0, n - 1]

Aus vielen der von mir gelesenen Antworten geht hervor, dass sie entweder eine Einheitlichkeit oder eine Halt-Garantie bieten, aber nicht beides (die zweite Antwort von Adam Rosenfeld könnte sein).

Dies ist jedoch möglich. Wir haben im Grunde diese Verteilung:

Rand5_proba.png

Dies lässt uns ein Loch in der Verteilung über [0-6]: 5 und 6 haben keine Wahrscheinlichkeit eines Auftretens. Stellen Sie sich jetzt vor, wir versuchen, das Loch zu füllen, indem wir die Wahrscheinlichkeitsverteilung verschieben und summieren.

In der Tat können wir die anfängliche Verteilung mit sich selbst um eins verschieben und wiederholen, indem wir die erhaltene Verteilung mit der anfänglichen um zwei, dann um drei usw. verschobenen Verteilung aufsummieren, bis 7 nicht enthalten sind (wir haben den gesamten Bereich abgedeckt). Dies ist in der folgenden Abbildung dargestellt. Die Reihenfolge der Farben entsprechend den Schritten ist blau -> grün -> cyan -> weiß -> magenta -> gelb -> rot.

fig_moving_average_proba.png

Da jeder Slot von 5 der 7 verschobenen Verteilungen abgedeckt wird (die Verschiebung variiert von 0 bis 6) und wir davon ausgehen, dass die Zufallszahlen unabhängig von einem Aufruf von ran5() zu einem anderen sind, erhalten wir

p(x) = 5 / 35 = 1 / 7       for all x in [0, 6]

Dies bedeutet, dass wir bei 7 unabhängigen Zufallszahlen aus ran5() eine Zufallszahl mit einheitlicher Wahrscheinlichkeit im Bereich [0-6] berechnen können. Tatsächlich muss die Wahrscheinlichkeitsverteilung von ran5 () nicht einmal einheitlich sein, solange die Stichproben unabhängig sind (sodass die Verteilung von Versuch zu Versuch gleich bleibt). Dies gilt auch für andere Nummern als 5 und 7.

Dies gibt uns die folgende python Funktion:

def Rand_range_transform(rands):
    """
    returns a uniform random number in [0, len(rands) - 1]
    if all r in rands are independent random numbers from the same uniform distribution
    """
    return sum((x + i) for i, x in enumerate(rands)) % len(rands) # a single modulo outside the sum is enough in modulo arithmetic

Dies kann wie folgt verwendet werden:

Rand5 = lambda : random.randrange(5)

def Rand7():
    return Rand_range_transform([Rand5() for _ in range(7)])

Wenn wir Rand7() 70000 mal aufrufen, erhalten wir:

max: 6 min: 0 mean: 2.99711428571 std: 2.00194697049
0:  10019
1:  10016
2:  10071
3:  10044
4:  9775
5:  10042
6:  10033

Das ist gut, aber alles andere als perfekt. Tatsache ist, dass eine unserer Annahmen bei dieser Implementierung höchstwahrscheinlich falsch ist: Wir verwenden ein PRNG, und daher ist das Ergebnis des nächsten Aufrufs vom letzten Ergebnis abhängig.

Unter Verwendung einer wirklich zufälligen Zahlenquelle sollte die Ausgabe jedoch auch wirklich zufällig sein. Und dieser Algorithmus endet in jedem Fall.

Dies ist jedoch mit Kosten verbunden: Wir benötigen 7 Aufrufe von Rand5() für einen einzelnen Rand7() -Aufruf.

2
bernard paulus

Diese Lösung verschwendet keine Entropie und liefert die erste wirklich zufällige Zufallszahl in Reichweite. Mit jeder Iteration wird die Wahrscheinlichkeit, keine Antwort zu erhalten, nachweislich verringert. Die Wahrscheinlichkeit, eine Antwort in N Iterationen zu erhalten, ist die Wahrscheinlichkeit, dass eine Zufallszahl zwischen 0 und max (5 ^ N) kleiner ist als das größte Vielfache von sieben in diesem Bereich (max-max% 7). Muss mindestens zweimal iterieren. Dies gilt jedoch zwangsläufig für alle Lösungen.

int random7() {
  range = 1;
  remainder = 0;

  while (1) {
    remainder = remainder * 5 + random5() - 1;
    range = range * 5;

    limit = range - (range % 7);
    if (remainder < limit) return (remainder % 7) + 1;

    remainder = remainder % 7;
    range = range % 7;
  }
}

Numerisch äquivalent zu:

r5=5;
num=random5()-1;
while (1) {
   num=num*5+random5()-1;
   r5=r5*5;
   r7=r5-r5%7;
   if (num<r7) return num%7+1;
}

Der erste Code berechnet es in Modulo-Form. Der zweite Code ist einfach mathematisch. Oder ich habe irgendwo einen Fehler gemacht. :-)

2
Martin
package CareerCup;

public class RangeTransform {
 static int counter = (int)(Math.random() * 5 + 1);

 private int func() {
  return (int) (Math.random() * 5 + 1);
 }

 private int getMultiplier() {
  return counter % 5 + 1;
 }

 public int rangeTransform() {
  counter++;
  int count = getMultiplier();
  int mult = func() + 5 * count;
  System.out.println("Mult is : " + 5 * count);
  return (mult) % 7 + 1;
 }

 /**
  * @param args
  */
 public static void main(String[] args) {
  // TODO Auto-generated method stub
  RangeTransform rangeTransform = new RangeTransform();
  for (int i = 0; i < 35; i++)
   System.out.println("Val is : " + rangeTransform.rangeTransform());
 }
}
2
DeWan

Wenn angenommen wird, dass Rand alle Bits gleich gewichtet, dann maskiert sie mit der oberen Grenze.

int i = Rand(5) ^ (Rand(5) & 2);

Rand(5) kann nur Folgendes zurückgeben: 1b, 10b, 11b, 100b, 101b. Sie müssen sich nur mit der Einstellung der 2-Bit-Einstellungen beschäftigen.

2
Ben
function Rand7
   put 200 into x
   repeat while x > 118
      put ((random(5)-1) * 25) + ((random(5)-1) * 5) + (random(5)-1) into x
   end repeat
   return (x mod 7) + 1
end Rand7

Drei Anrufe an Rand5, die durchschnittlich nur 6-mal von 125 wiederholt werden.

Stellen Sie sich dies als ein 3D-Array vor, 5x5x5, gefüllt mit 1 bis 7 Wiederholungen und 6 Leerzeichen. Rolle auf den Zuschnitten erneut. Die Rand5-Aufrufe erstellen einen dreistelligen Base-5-Index in diesem Array.

Mit 4D oder mehr N-dimensionalen Arrays gibt es weniger Wiederholungen. Dies bedeutet jedoch, dass mehr Aufrufe der Funktion Rand5 zum Standard werden. Bei höheren Dimensionen werden Sie mit sinkenden Wirkungsgraden rechnen. Drei scheint mir ein guter Kompromiss zu sein, aber ich habe sie nicht gegeneinander getestet. Und es wäre spezifisch für die Rand5-Implementierung.

2
user470894

Warum funktioniert das nicht? Anderer als der extra Anruf nach Rand5 ()?

i = Rand5() + Rand5() + (Rand5() - 1) //Random number between 1 and 14

i = i % 7 + 1;
2
Sam

Dies ist die einfachste Antwort, die ich nach dem Überprüfen der Antworten anderer erstellen könnte:

def r5tor7():
    while True:
        cand = (5 * r5()) + r5()
        if cand < 27:
            return cand

cand liegt im Bereich [6, 27] und die möglichen Ergebnisse sind gleichmäßig verteilt, wenn die möglichen Ergebnisse von r5 () gleichmäßig verteilt sind. Sie können meine Antwort mit diesem Code testen:

from collections import defaultdict

def r5_outcome(n):
    if not n:
        yield []
    else:
        for i in range(1, 6):
            for j in r5_outcome(n-1):
                yield [i] + j

def test_r7():
    d = defaultdict(int)
    for x in r5_outcome(2):
        s = sum([x[i] * 5**i for i in range(len(x))])
        if s < 27:
            d[s] += 1
    print len(d), d

r5_outcome(2) generiert alle möglichen Kombinationen von r5 () - Ergebnissen. Ich verwende denselben Filter zum Testen wie in meinem Lösungscode. Sie können sehen, dass alle Ergebnisse gleichermaßen wahrscheinlich sind, weil sie den gleichen Wert haben.

2
hughdbrown

Folgendes habe ich gefunden:

  1. Random5 erzeugt einen Bereich von 1 bis 5, der zufällig verteilt ist
  2. Wenn wir es dreimal ausführen und sie zusammen hinzufügen, erhalten wir einen Bereich von 3 ~ 15, der zufällig verteilt ist
  3. Führen Sie die Arithmetik im Bereich 3 ~ 15 aus
    1. (3 ~ 15) - 1 = (2 ~ 14)
    2. (2 ~ 14)/2 = (1 ~ 7)

Dann erhalten wir einen Bereich von 1 ~ 7, also die von uns gesuchte Random7.

2
ming_codes

Hier ist meine allgemeine Implementierung, um eine Uniform im Bereich [0, N-1] bei einem einheitlichen Generator im Bereich [0, B-1] zu erzeugen. 

public class RandomUnif {

    public static final int BASE_NUMBER = 5;

    private static Random Rand = new Random();

    /** given generator, returns uniform integer in the range 0.. BASE_NUMBER-1
    public static int randomBASE() {
        return Rand.nextInt(BASE_NUMBER);
    }

    /** returns uniform integer in the range 0..n-1 using randomBASE() */
    public static int randomUnif(int n) {
        int Rand, factor;
        if( n <= 1 ) return 0;
        else if( n == BASE_NUMBER ) return randomBASE();
        if( n < BASE_NUMBER ) {
            factor = BASE_NUMBER / n;
            do
                Rand = randomBASE() / factor;
            while(Rand >= n);
            return Rand;
        } else {
            factor = (n - 1) / BASE_NUMBER + 1;
            do {
                Rand = factor * randomBASE() + randomUnif(factor);
            } while(Rand >= n);
            return Rand;
        }
    }
}

Nicht spektakulär, aber allgemein und kompakt. Mittlere Aufrufe des Basisgenerators:

 n  calls
 2  1.250 
 3  1.644 
 4  1.252 
 5  1.000 
 6  3.763 
 7  3.185 
 8  2.821 
 9  2.495 
10  2.250 
11  3.646 
12  3.316 
13  3.060 
14  2.853 
15  2.650 
16  2.814 
17  2.644 
18  2.502 
19  2.361 
20  2.248 
21  2.382 
22  2.277 
23  2.175 
24  2.082 
25  2.000 
26  5.472 
27  5.280 
28  5.119 
29  4.899 
1
leonbloy
  1. Was ist eine einfache Lösung? (Rand5() + Rand5()) % 7 + 1
  2. Was ist eine effektive Lösung, um die Speichernutzung zu reduzieren oder auf einer langsameren CPU zu laufen? Yes, this is effective as it calls Rand5() only twice and have O(1) space complexity

Betrachten Sie Rand5() gibt Zufallszahlen von 1 bis 5 (einschließlich) aus.
(1 + 1)% 7 + 1 = 3
[...] (1 + 2)% 7 + 1 = 4
[...] (1 + 3)% 7 + 1 = 5
(1 + 4)% 7 + 1 = 6
[...] (1 + 5)% 7 + 1 = 7

(2 + 1)% 7 + 1 = 4
[...] (2 + 2)% 7 + 1 = 5
[...] (2 + 3)% 7 + 1 = 6
[...] (2 + 4)% 7 + 1 = 7
[...] (2 + 5)% 7 + 1 = 1
...

(5 + 1)% 7 + 1 = 7
[...] (5 + 2)% 7 + 1 = 1
[...] (5 + 3)% 7 + 1 = 2
[...] (5 + 4)% 7 + 1 = 3
[...] (5 + 5)% 7 + 1 = 4
...

und so weiter

1
Devendra Lattu

Das erste, was mir in den Sinn kam, ist folgendes. Aber ich habe keine Ahnung, ob es gleichmäßig verteilt ist. In Python implementiert

zufällig importieren

def Rand5 ():

zufällig zurückgeben.randint (1,5)

def Rand7 ():

return (((Rand5 () -1)) * Rand5 ())% 7) +1

1
HOT

Kam hier von einem Link aus der Erweiterung eines Float-Bereichs. Das macht mehr Spaß. Anstatt wie ich zu dem Schluss gekommen bin, kam mir der Gedanke, dass für eine gegebene Zufallsgeneratorfunktion f mit "base" b (4 in diesem Fall, ich sage warum) diese Funktion wie folgt erweitert werden kann :

(b^0 * f() + b^1 * f() + b^2 * f() .... b^p * f()) / (b^(p+1) - 1) * (b-1)

Dadurch wird ein Zufallsgenerator in einen FLOAT-Generator umgewandelt. Ich werde hier 2 Parameter definieren, die b und die p. Obwohl die "Basis" hier 4 ist, kann b tatsächlich alles sein, es kann sich auch um eine irrationale Zahl usw. handeln. p, ich nenne Präzision ein Maß dafür, wie genau Ihr Float-Generator sein soll. Stellen Sie sich dies als Anzahl der Anrufe vor, die für jeden Aufruf von Rand5 an Rand7 getätigt wurden.

Aber ich habe erkannt, dass wenn Sie b auf Basis + 1 setzen (was in diesem Fall 4 + 1 = 5 ist), dies ein guter Punkt ist und Sie eine gleichmäßige Verteilung erhalten. Zuerst diesen 1-5 Generator loswerden, es ist in Wahrheit Rand4 () + 1:

function Rand4(){
    return Math.random() * 5 | 0;
}

Um dorthin zu gelangen, können Sie Rand4 durch Rand5()-1 ersetzen.

Als nächstes wird Rand4 von einem Integer-Generator in einen Float-Generator umgewandelt

function toFloat(f,b,p){
    b = b || 2;
    p = p || 3;
    return (Array.apply(null,Array(p))
    .map(function(d,i){return f()})
    .map(function(d,i){return Math.pow(b,i)*d})
    .reduce(function(ac,d,i){return ac += d;}))
    /
    (
        (Math.pow(b,p) - 1)
        /(b-1)
    )
}

Dies wird die erste Funktion, die ich geschrieben habe, auf eine bestimmte Rand-Funktion anwenden. Versuch es:

toFloat(Rand4) //1.4285714285714286 base = 2, precision = 3
toFloat(Rand4,3,4) //0.75 base = 3, precision = 4
toFloat(Rand4,4,5) //3.7507331378299122 base = 4, precision = 5
toFloat(Rand4,5,6) //0.2012288786482335 base = 5, precision =6
...

Jetzt können Sie diesen Float-Bereich (0-4 INCLUSIVE) in einen anderen Float-Bereich konvertieren und ihn dann zu einer Ganzzahl herabstufen. Hier ist unsere Basis 4, weil wir es mit Rand4 zu tun haben, daher gibt Ihnen ein Wert b=5 eine einheitliche Verteilung. Wenn b nach 4 wächst, werden Sie periodische Lücken in der Verteilung einführen. Ich habe für b Werte zwischen 2 und 8 mit jeweils 3000 Punkten getestet und im Vergleich zu native Math.random von Javascript, sieht für mich sogar noch besser aus als die native selbst:

http://jsfiddle.net/ibowankenobi/r57v432t/

Klicken Sie für den obigen Link auf die Schaltfläche "bin" oben in den Verteilungen, um die Binning-Größe zu verringern. Der letzte Graph ist native Math.random, der vierte, bei dem d = 5 gleichförmig ist.

Nachdem Sie Ihren Float-Bereich erhalten haben, multiplizieren Sie entweder mit 7 und werfen Sie den Dezimalteil oder multiplizieren Sie mit 7, subtrahieren Sie 0,5 und runden Sie ab:

((toFloat(Rand4,5,6)/4 * 7) | 0) + 1   ---> occasionally you'll get 8 with 1/4^6 probability.
Math.round((toFloat(Rand4,5,6)/4 * 7) - 0.5) + 1 --> between 1 and 7
1

Ich dachte an eine interessante Lösung für dieses Problem und wollte es teilen.

function Rand7() {

    var returnVal = 4;

    for (var n=0; n<3; n++) {
        var Rand = Rand5();

        if (Rand==1||Rand==2){
            returnVal+=1;
        }
        else if (Rand==3||Rand==4) {
            returnVal-=1;
        }
    }

    return returnVal;
}

Ich habe eine Testfunktion erstellt, die Rand7 () 10.000 Mal durchläuft, alle Rückgabewerte summiert und durch 10.000 dividiert. Wenn Rand7 () korrekt arbeitet, sollte unser berechneter Durchschnitt 4 sein - zum Beispiel (1 + 2 + 3 + 4 + 5 + 6 + 7/7) = 4. Nach mehreren Tests liegt der Durchschnitt tatsächlich bei 4 :)

1
Eric Rowell

Es gibt viele Lösungen, die keine einheitliche Verteilung erzeugen, und viele Kommentare, die darauf hinweisen, aber die die Frage stellt dies nicht als Anforderung dar . Die einfachste Lösung ist:

int Rand_7() { return Rand_5(); }

Eine zufällige ganze Zahl im Bereich von 1 bis 5 liegt eindeutig im Bereich von 1 bis 7. Nun, technisch gesehen ist die einfachste Lösung, eine Konstante zurückzugeben, aber das ist zu trivial. 

Ich glaube jedoch, dass die Funktion Rand_5 ein roter Hering ist. Angenommen, die Frage wurde gestellt als "Erzeugen eines gleichverteilten Pseudozufallszahlengenerators mit ganzzahliger Ausgabe im Bereich 1 - 7". Das ist ein einfaches Problem (nicht technisch einfach, aber bereits gelöst, sodass Sie es nachschlagen können.) 

Wenn die Frage dahingehend interpretiert wird, dass Sie tatsächlich einen echten Zufallszahlengenerator für Ganzzahlen im Bereich von 1 bis 5 (nicht Pseudo-Zufall) haben, lautet die Lösung:

1) examine the Rand_5 function
2) understand how it works
3) profit
1
William Pursell

wie wäre es damit

Rand5 ()% 2 + Rand5 ()% 2 + Rand5 ()% 2 + Rand5 ()% 2 + Rand5 ()% 2 + Rand5 ()% 2

Nicht sicher, ob dies gleichmäßig verteilt ist. Irgendwelche Vorschläge?

1
rich

Eine andere Antwort, die hier offenbar nicht behandelt wurde:

int Rand7() {
  int r = 7 / 2;
  for (int i = 0; i < 28; i++)
    r = ((Rand5() - 1) * 7 + r) / 5;
  return r + 1;
}

Bei jeder Iteration ist r ein zufälliger Wert zwischen 0 und einschließlich 6. Dies wird an einen Zufallswert zwischen 0 und einschließlich 4 angehängt (Basis 7), und das Ergebnis wird durch 5 geteilt, wodurch ein neuer Zufallswert im Bereich von 0 bis einschließlich 6 erhalten wird. r beginnt mit einer erheblichen Verzerrung (r = 3 ist sehr verzerrt!), aber jede Wiederholung teilt diese Verzerrung durch 5.

Diese Methode ist nicht vollkommen gleichförmig; Die Vorspannung ist jedoch verschwindend gering. Etwas in der Größenordnung von 1/(2 ** 64). Bei diesem Ansatz ist es wichtig, dass er eine konstante Ausführungszeit hat (vorausgesetzt, Rand5() hat auch eine konstante Ausführungszeit). Keine theoretischen Bedenken, dass ein unglücklicher Anruf die Suche nach schlechten Werten für immer durchlaufen könnte.


Auch eine sarkastische Antwort für ein gutes Maß (absichtlich oder nicht, es wurde abgedeckt):

1-5 liegt bereits im Bereich von 1-7, daher ist Folgendes eine gültige Implementierung:

int Rand7() {
  return Rand5();
}

Frage nicht um einheitliche Verteilung gebeten.

1
sh1

Ich denke, ich habe vier Antworten, zwei geben exakte Lösungen wie die von @Adam Rosenfield aber ohne das unendliche Schleifenproblem, und zwei mit fast perfekter Lösung, aber schnellerer Implementierung als die erste. 

Die beste exakte Lösung erfordert 7 Aufrufe von Rand5

Methode 1 - genau

Die Stärke von Adams Antwort ist, dass sie eine perfekte gleichmäßige Verteilung ergibt, und es besteht eine sehr hohe Wahrscheinlichkeit (21/25), dass nur zwei Aufrufe von Rand5 () erforderlich sind. Der schlimmste Fall ist jedoch eine Endlosschleife. 

Die erste Lösung unten bietet auch eine perfekte gleichmäßige Verteilung, erfordert jedoch insgesamt 42 Aufrufe von Rand5. Keine unendlichen Schleifen.

Hier ist eine R-Implementierung:

Rand5 <- function() sample(1:5,1)

Rand7 <- function()  (sum(sapply(0:6, function(i) i + Rand5() + Rand5()*2 + Rand5()*3 + Rand5()*4 + Rand5()*5 + Rand5()*6)) %% 7) + 1

Für Personen, die nicht mit R vertraut sind, hier eine vereinfachte Version:

Rand7 = function(){
  r = 0 
  for(i in 0:6){
    r = r + i + Rand5() + Rand5()*2 + Rand5()*3 + Rand5()*4 + Rand5()*5 + Rand5()*6
  }
  return r %% 7 + 1
}

Die Verteilung von Rand5 bleibt erhalten. Wenn wir rechnen, hat jede der 7 Iterationen der Schleife 5 ^ 6 mögliche Kombinationen, daher ist die Gesamtzahl der möglichen Kombinationen (7 * 5^6) %% 7 = 0. Daher können wir die erzeugten Zufallszahlen in gleich große Gruppen von 7 teilen. Siehe hierzu die zweite Methode.

Hier sind alle möglichen Kombinationen:

table(apply(expand.grid(c(outer(1:5,0:6,"+")),(1:5)*2,(1:5)*3,(1:5)*4,(1:5)*5,(1:5)*6),1,sum) %% 7 + 1)

    1     2     3     4     5     6     7 
15625 15625 15625 15625 15625 15625 15625 

Ich denke, es ist einfach zu zeigen, dass Adams Methode viel schneller laufen wird. Die Wahrscheinlichkeit, dass in Adams Lösung Rand5 42 oder mehr Anrufe tätigen, ist sehr gering ((4/25)^21 ~ 10^(-17)). 

Methode 2 - Nicht genau

Nun die zweite Methode, die fast einheitlich ist, aber 6 Aufrufe von Rand5 erfordert:

Rand7 <- function() (sum(sapply(1:6,function(i) i*Rand5())) %% 7) + 1

Hier ist eine vereinfachte Version:

Rand7 = function(){
  r = 0 
  for(i in 1:6){
    r = r + i*Rand5()
  }
  return r %% 7 + 1
}

Dies ist im Wesentlichen eine Iteration von Methode 1. Wenn wir alle möglichen Kombinationen generieren, ergibt sich daraus folgende Anzahl:

table(apply(expand.grid(1:5,(1:5)*2,(1:5)*3,(1:5)*4,(1:5)*5,(1:5)*6),1,sum) %% 7 + 1)

   1    2    3    4    5    6    7 
2233 2232 2232 2232 2232 2232 2232

Eine Zahl wird in 5^6 = 15625-Versuchen erneut angezeigt.

Nun verschieben wir in Methode 1 durch Hinzufügen von 1 zu 6 die Zahl 2233 zu jedem der nachfolgenden Punkte. Somit wird die Gesamtzahl der Kombinationen übereinstimmen. Dies funktioniert, weil 5 ^ 6 %% 7 = 1, und dann machen wir 7 geeignete Variationen, also (7 * 5 ^ 6 %% 7 = 0). 

Methode 3 - Genau

Wenn das Argument von Methode 1 und 2 verstanden wird, folgt Methode 3 und erfordert nur 7 Aufrufe von Rand5. An diesem Punkt glaube ich, dass dies die Mindestanzahl von Anrufen ist, die für eine genaue Lösung erforderlich sind.

Hier ist eine R-Implementierung:

Rand5 <- function() sample(1:5,1)

Rand7 <- function()  (sum(sapply(1:7, function(i) i * Rand5())) %% 7) + 1

Für Personen, die nicht mit R vertraut sind, hier eine vereinfachte Version:

Rand7 = function(){
  r = 0 
  for(i in 1:7){
    r = r + i * Rand5()
  }
  return r %% 7 + 1
}

Die Verteilung von Rand5 bleibt erhalten. Wenn wir rechnen, hat jede der 7 Iterationen der Schleife 5 mögliche Ergebnisse. Die Gesamtzahl der möglichen Kombinationen ist (7 * 5) %% 7 = 0. Daher können wir die erzeugten Zufallszahlen in gleiche Gruppen von 7 unterteilen. Siehe dazu die Methoden eins und zwei.

Hier sind alle möglichen Kombinationen:

table(apply(expand.grid(0:6,(1:5)),1,sum) %% 7 + 1)

1 2 3 4 5 6 7  
5 5 5 5 5 5 5 

Ich denke, es ist einfach zu zeigen, dass Adams Methode noch schneller läuft. Die Wahrscheinlichkeit, dass in Adams Lösung Rand5 mindestens sieben Anrufe getätigt werden, ist immer noch gering ((4/25)^3 ~ 0.004). 

Methode 4 - Nicht genau

Dies ist eine geringfügige Variante der zweiten Methode. Es ist fast einheitlich, erfordert aber 7 Aufrufe von Rand5, das ist eine zusätzliche Methode von Methode 2:

Rand7 <- function() (Rand5() + sum(sapply(1:6,function(i) i*Rand5())) %% 7) + 1

Hier ist eine vereinfachte Version:

Rand7 = function(){
  r = 0 
  for(i in 1:6){
    r = r + i*Rand5()
  }
  return (r+Rand5()) %% 7 + 1
}

Wenn wir alle möglichen Kombinationen generieren, ergibt sich daraus folgende Anzahl:

table(apply(expand.grid(1:5,(1:5)*2,(1:5)*3,(1:5)*4,(1:5)*5,(1:5)*6,1:5),1,sum) %% 7 + 1)

    1     2     3     4     5     6     7 
11160 11161 11161 11161 11161 11161 11160

Zwei Nummern erscheinen einmal weniger in 5^7 = 78125-Versuchen. Für die meisten Zwecke kann ich damit leben.

1
Shambho

Diese Lösung wurde von Rob McAfee inspiriert.
Es wird jedoch keine Schleife benötigt und das Ergebnis ist eine gleichmäßige Verteilung:

// Returns 1-5
var rnd5 = function(){
   return parseInt(Math.random() * 5, 10) + 1;
}
// Helper
var lastEdge = 0;
// Returns 1-7
var rnd7 = function () {
  var map = [
     [ 1, 2, 3, 4, 5 ],
     [ 6, 7, 1, 2, 3 ],
     [ 4, 5, 6, 7, 1 ],
     [ 2, 3, 4, 5, 6 ],
     [ 7, 0, 0, 0, 0 ]
  ];
  var result = map[rnd5() - 1][rnd5() - 1];
  if (result > 0) {
    return result;
  }
  lastEdge++;
  if (lastEdge > 7 ) {
    lastEdge = 1;
  }
  return lastEdge;
};

// Test the a uniform distribution
results = {}; for(i=0; i < 700000;i++) { var Rand = rnd7(); results[Rand] = results[Rand] ? results[Rand] + 1 : 1;} 
console.log(results)

Ergebnis: [1: 99560, 2: 99932, 3: 100355, 4: 100262, 5: 99603, 6: 100062, 7: 100226]

jsFiddle

1
jantimon
function Rand7() {
    while (true) { //lowest base 5 random number > 7 reduces memory
        int num = (Rand5()-1)*5 + Rand5()-1;
    if (num < 21)  // improves performance
        return 1 + num%7;
    }
}

Python-Code:

from random import randint
def Rand7():
    while(True):
        num = (randint(1, 5)-1)*5 + randint(1, 5)-1
        if num < 21:
                return 1 + num%7

Testverteilung für 100000 Läufe:

>>> rnums = []
>>> for _ in range(100000):
    rnums.append(Rand7())
>>> {n:rnums.count(n) for n in set(rnums)}
{1: 15648, 2: 15741, 3: 15681, 4: 15847, 5: 15642, 6: 15806, 7: 15635}
1
dansalmo

Schreiben Sie eine Funktion, die eine zufällige Ganzzahl im Bereich von 1 bis 5 erzeugt Rand5(), und geben Sie eine Funktion an, die eine zufällige Ganzzahl im Bereich von 1 bis 7 erzeugt Rand7()

In meiner vorgeschlagenen Lösung rufe ich Rand5 Nur einmal auf

echte Lösung

float Rand7()
{
    return (Rand5() * 7.0) / 5.0 ;
}

Die Verteilung hier ist skaliert, es kommt also direkt auf die Verteilung von Rand5 An

Ganzzahlige Lösung

int Rand7()
{
    static int prev = 1;

    int cur = Rand5();

    int r = cur * prev; // 1-25

    float f = r / 4.0; // 0.25-6.25

    f = f - 0.25; // 0-6

    f = f + 1.0; // 1-7

    prev = cur;

    return (int)f;
}

Die Verteilung hier ist abhängig von der Reihe Rand7(i) ~ Rand5(i) * Rand5(i-1)

mit Rand7(0) ~ Rand5(0) * 1

1
Khaled.K

Hier finden Sie eine Antwort, indem Sie die Funktionen von C++ 11 nutzen

#include <functional>
#include <iostream>
#include <ostream>
#include <random>

int main()
{
    std::random_device rd;
    unsigned long seed = rd();
    std::cout << "seed = " << seed << std::endl;

    std::mt19937 engine(seed);

    std::uniform_int_distribution<> dist(1, 5);
    auto Rand5 = std::bind(dist, engine);

    const int n = 20;
    for (int i = 0; i != n; ++i)
    {
        std::cout << Rand5() << " ";
    }
    std::cout << std::endl;

    // Use a lambda expression to define Rand7
    auto Rand7 = [&Rand5]()->int
    {
        for (int result = 0; ; result = 0)
        {
            // Take advantage of the fact that
            // 5**6 = 15625 = 15624 + 1 = 7 * (2232) + 1.
            // So we only have to discard one out of every 15625 numbers generated.

            // Generate a 6-digit number in base 5
            for (int i = 0; i != 6; ++i)
            {
                result = 5 * result + (Rand5() - 1);
            }

            // result is in the range [0, 15625)
            if (result == 15625 - 1)
            {
                // Discard this number
                continue;
            }

            // We now know that result is in the range [0, 15624), a range that can
            // be divided evenly into 7 buckets guaranteeing uniformity
            result /= 2232;
            return 1 + result;
        }
    };

    for (int i = 0; i != n; ++i)
    {
        std::cout << Rand7() << " ";
    }
    std::cout << std::endl;

    return 0;
}
1
user515430
int Rand7()
{
    return ( Rand5() + (Rand5()%3) );
}
  1. Rand5 () - Gibt Werte von 1-5 zurück
  2. Rand5 ()% 3 - Gibt Werte von 0-2 zurück
  3. Bei der Summierung liegt der Gesamtwert also zwischen 1 und 7
1
prabhakcv

Dies ist ähnlich wie bei @RobMcAfee, nur dass ich eine magische Zahl anstelle eines zweidimensionalen Arrays verwende.

int Rand7() {
    int m = 1203068;
    int r = (m >> (Rand5() - 1) * 5 + Rand5() - 1) & 7;

    return (r > 0) ? r : Rand7();
}
1
invisal

Ich denke, Sie denken darüber nach. Funktioniert diese einfache Lösung nicht?

int Rand7(void)
{
    static int startpos = 0;
    startpos = (startpos+5) % (5*7);
    return (((startpos + Rand5()-1)%7)+1);
}
1
Graham Toal

Wäre cool, wenn mir jemand Feedback geben könnte, ich habe JUNIT ohne Assert Pattern verwendet, weil es einfach und schnell in Eclipse zum Laufen gebracht wird. Ich hätte auch eine Hauptmethode definieren können. Ich gehe übrigens davon aus, dass Rand5 die Werte 0-4 ergibt, das Hinzufügen von 1 würde die Werte 1-5 ergeben, genauso wie bei Rand7 ... Die Diskussion sollte sich also auf die Lösung beziehen oder 1-5 ...

package random;

import Java.util.Random;

import org.junit.Test;

public class RandomTest {


    @Test
    public void testName() throws Exception {
        long times = 100000000;
        int indexes[] = new int[7];
        for(int i = 0; i < times; i++) {
            int Rand7 = Rand7();
            indexes[Rand7]++;
        }

        for(int i = 0; i < 7; i++)
            System.out.println("Value " + i + ": " + indexes[i]);
    }


    public int Rand7() {
        return (Rand5() + Rand5() + Rand5() + Rand5() + Rand5() + Rand5() + Rand5()) % 7;
    }


    public int Rand5() {
        return new Random().nextInt(5);
    }


}

Wenn ich es starte, bekomme ich dieses Ergebnis:

Value 0: 14308087
Value 1: 14298303
Value 2: 14279731
Value 3: 14262533
Value 4: 14269749
Value 5: 14277560
Value 6: 14304037

Dies scheint eine sehr faire Verteilung zu sein, nicht wahr?

Wenn ich Rand5 () weniger oder mehrmals hinzufüge (wobei die Anzahl der Zeiten nicht durch 7 teilbar ist), zeigt die Verteilung Offsets. Fügen Sie beispielsweise Rand5() dreimal hinzu:

Value 0: 15199685
Value 1: 14402429
Value 2: 12795649
Value 3: 12796957
Value 4: 14402252
Value 5: 15202778
Value 6: 15200250

Das würde also zu folgendem führen:

public int Rand(int range) {
    int randomValue = 0;
    for(int i = 0; i < range; i++) {
        randomValue += Rand5();
    }
    return randomValue % range;

}

Und dann könnte ich noch weiter gehen:

public static final int ORIGN_RANGE = 5;
public static final int DEST_RANGE  = 7;

@Test
public void testName() throws Exception {
    long times = 100000000;
    int indexes[] = new int[DEST_RANGE];
    for(int i = 0; i < times; i++) {
        int Rand7 = convertRand(DEST_RANGE, ORIGN_RANGE);
        indexes[Rand7]++;
    }

    for(int i = 0; i < DEST_RANGE; i++)
        System.out.println("Value " + i + ": " + indexes[i]);
}


public int convertRand(int destRange, int originRange) {
    int randomValue = 0;
    for(int i = 0; i < destRange; i++) {
        randomValue += Rand(originRange);
    }
    return randomValue % destRange;

}


public int Rand(int range) {
    return new Random().nextInt(range);
}

Ich habe dies versucht, um destRange und originRange durch verschiedene Werte zu ersetzen (sogar 7 für Origin und 13 für DEST), und ich bekomme diese Verteilung:

Value 0: 7713763
Value 1: 7706552
Value 2: 7694697
Value 3: 7695319
Value 4: 7688617
Value 5: 7681691
Value 6: 7674798
Value 7: 7680348
Value 8: 7685286
Value 9: 7683943
Value 10: 7690283
Value 11: 7699142
Value 12: 7705561

Was ich daraus schließen kann, ist, dass Sie beliebige Zufallszahlen ändern können, indem Sie die "Zufallszeiten" von Origin zufällig summieren. Dies wird eine Art Gaußsche Verteilung erhalten (die mittleren Werte sind wahrscheinlicher und die Edge-Werte ungewöhnlicher). Der Bestimmungsmodul scheint sich jedoch gleichmäßig über diese Gaußsche Verteilung zu verteilen ... Es wäre toll, Feedback von einem Mathematiker zu bekommen ... 

Was cool ist, ist, dass die Kosten zu 100% vorhersehbar und konstant sind, während andere Lösungen eine geringe Wahrscheinlichkeit einer unendlichen Schleife verursachen.

0
Martin

Zuerst bewege ich ramdom5 () 6 Mal auf den 1 Punkt, um 7 Zufallszahlen zu erhalten. Zweitens füge ich 7 Zahlen hinzu, um eine gemeinsame Summe zu erhalten. Drittens bekomme ich den Rest der Division bei 7 . Zuletzt addiere ich 1, um Ergebnisse von 1 bis 7 zu erhalten. mit der Ausnahme von 1. 1 hat eine etwas höhere Wahrscheinlichkeit.

public int random7(){
    Random random = new Random();
    //function (1 + random.nextInt(5)) is given
    int random1_5 = 1 + random.nextInt(5); // 1,2,3,4,5
    int random2_6 = 2 + random.nextInt(5); // 2,3,4,5,6
    int random3_7 = 3 + random.nextInt(5); // 3,4,5,6,7
    int random4_8 = 4 + random.nextInt(5); // 4,5,6,7,8
    int random5_9 = 5 + random.nextInt(5); // 5,6,7,8,9
    int random6_10 = 6 + random.nextInt(5); //6,7,8,9,10
    int random7_11 = 7 + random.nextInt(5); //7,8,9,10,11

    //sumOfRandoms is between 28 and 56
    int sumOfRandoms = random1_5 + random2_6 + random3_7 + 
                       random4_8 + random5_9 + random6_10 + random7_11;
    //result is number between 0 and 6, and
    //equals 0 if sumOfRandoms = 28 or 35 or 42 or 49 or 56 , 5 options
    //equals 1 if sumOfRandoms = 29 or 36 or 43 or 50, 4 options
    //equals 2 if sumOfRandoms = 30 or 37 or 44 or 51, 4 options
    //equals 3 if sumOfRandoms = 31 or 38 or 45 or 52, 4 options
    //equals 4 if sumOfRandoms = 32 or 39 or 46 or 53, 4 options
    //equals 5 if sumOfRandoms = 33 or 40 or 47 or 54, 4 options
    //equals 6 if sumOfRandoms = 34 or 41 or 48 or 55, 4 options
    //It means that the probabilities of getting numbers between 0 and 6 are almost equal.
    int result = sumOfRandoms % 7;
    //we should add 1 to move the interval [0,6] to the interval [1,7]
    return 1 + result;
}
0
Michael Katkov

Hier ist meins, dies versucht, Math.random() aus mehreren Rand5() Funktionsaufrufen wiederherzustellen, wobei ein Einheitsintervall (der Ausgabebereich von Math.random()) durch Rekonstruktion mit "gewichteten Brüchen" (?) Rekonstruiert wird. Verwenden Sie dann dieses zufällige Einheitsintervall, um eine zufällige ganze Zahl zwischen 1 und 7 zu erzeugen:

function Rand5(){
  return Math.floor(Math.random()*5)+1;
}
function Rand7(){
  var uiRandom=0;
  var div=1;
  for(var i=0; i<7; i++){
    div*=5;
    var term=(Rand5()-1)/div;
    uiRandom+=term;
  }
  //return uiRandom;
  return Math.floor(uiRandom*7)+1; 
}

Um es auszudrücken: Wir nehmen zufällige Ganzzahlen zwischen 0-4 (nur Rand5()-1) und multiplizieren jedes Ergebnis mit 1/5, 1/25, 1/125, ... und addieren sie dann. Es ist ähnlich wie bei binär gewichteten Brüchen; Ich nehme an, wir nennen es stattdessen einen quinären (Basis-5) gewichteten Bruch: Eine Zahl von 0 - 0,999999 als eine Serie von (1/5) ^ n Ausdrücken.

Es sollte trivial sein, die Funktion so zu ändern, dass ein beliebiger Ein-/Ausgabe-Ganzzahlbereich angenommen wird. Der obige Code kann optimiert werden, wenn er als Abschluss überschrieben wird.


Alternativ können wir auch folgendes tun:

function Rand5(){
  return Math.floor(Math.random()*5)+1;
}
function Rand7(){
  var buffer=[];
  var div=1;
  for (var i=0; i<7; i++){
    buffer.Push((Rand5()-1).toString(5));
    div*=5;
  }
  var n=parseInt(buffer.join(""),5);
  var uiRandom=n/div;
  //return uiRandom;
  return Math.floor(uiRandom*7)+1; 
}

Anstatt mit dem Aufbau einer gewichteten Fraktion (Basis-5) zu fummeln, erstellen wir tatsächlich eine binäre Zahl, die in eine Fraktion umgewandelt wird (0--0.9999 ... wie zuvor). Dann berechnen wir unsere zufällige 1-7-Ziffer von dort.

Ergebnisse für oben (Code-Snippet # 2: 3-Läufe von jeweils 100.000 Anrufen):

1: 14263; 2: 14414; 3: 14249; 4: 14109; 5: 14217; 6: 14361; 7: 14387

1: 14205; 2: 14394; 3: 14238; 4: 14187; 5: 14384; 6: 14224; 7: 14368

1: 14425; 2: 14236; 3: 14334; 4: 14232; 5: 14160; 6: 14320; 7: 14293

0
jongo45

Warum dividiert man nicht einfach durch 5 und multipliziert mit 7 und dann rund? (Zugegeben, Sie müssten Gleitkommazahlen verwenden.)

Es ist viel einfacher und zuverlässiger als die anderen Lösungen. Z.B. in Python:

def ranndomNo7():
    import random
    Rand5 = random.randint(4)    # Produces range: [0, 4]
    Rand7 = int(Rand5 / 5 * 7)   # /5, *7, +0.5 and floor()
    return Rand7

War das nicht einfach?

0

Die einfache Lösung wurde gut abgedeckt: Nehmen Sie zwei random5-Samples für ein random7-Ergebnis und wiederholen Sie es, wenn das Ergebnis außerhalb des Bereichs liegt, der eine gleichmäßige Verteilung erzeugt. Wenn Sie die Anzahl der Aufrufe von random5 reduzieren möchten, ist dies äußerst verschwenderisch. Die durchschnittliche Anzahl der Aufrufe von random5 für jede random7-Ausgabe beträgt 2.38 anstelle von 2, was auf die Anzahl der verworfenen Proben zurückzuführen ist.

Sie können das besser tun, indem Sie mehrere random5-Eingaben verwenden, um mehr als eine random7-Ausgabe gleichzeitig zu generieren. Bei Ergebnissen, die mit einer 31-Bit-Ganzzahl berechnet werden, ergibt sich das Optimum, wenn 12 Aufrufe von random5 zur Erzeugung von 9 random7-Ausgaben verwendet werden, wobei durchschnittlich 1,34 Aufrufe pro Ausgabe erfolgen. Dies ist effizient, da nur 2018983 von 244140625 Ergebnissen verschrottet werden müssen oder weniger als 1%.

Demo in Python:

def random5():
    return random.randint(1, 5)

def random7gen(n):
    count = 0
    while n > 0:
        samples = 6 * 7**9
        while samples >= 6 * 7**9:
            samples = 0
            for i in range(12):
                samples = samples * 5 + random5() - 1
                count += 1
        samples //= 6
        for outputs in range(9):
            yield samples % 7 + 1, count
            samples //= 7
            count = 0
            n -= 1
            if n == 0: break

>>> from collections import Counter
>>> Counter(x for x,i in random7gen(10000000))
Counter({2: 1430293, 4: 1429298, 1: 1428832, 7: 1428571, 3: 1428204, 5: 1428134, 6: 1426668})
>>> sum(i for x,i in random7gen(10000000)) / 10000000.0
1.344606
0
Mark Ransom

die Hauptauffassung dieses Problems bezieht sich auf die Normalverteilung. Hier wurde eine einfache und rekursive Lösung für dieses Problem bereitgestellt

nehmen wir an, wir haben Rand5() bereits in unserem Umfang:

def Rand7():
    # twoway = 0 or 1 in the same probability
    twoway = None
    while not twoway in (1, 2):
        twoway = Rand5()
    twoway -= 1

    ans = Rand5() + twoway * 5

    return ans if ans in range(1,8) else Rand7()

Erläuterung

Wir können dieses Programm in zwei Teile teilen:

  1. rand5 () bis wir 1 oder 2 gefunden haben, bedeutet, dass wir die Wahrscheinlichkeit haben, 1 oder 2 in der Variablen twoway zu haben.
  2. composite ans von Rand5() + twoway * 5, das ist genau das Ergebnis von Rand10(). Wenn dies nicht zu unserem Bedarf (1 ~ 7) passt, führen wir Rand7 erneut aus.

P.S. wir können nicht direkt eine while-Schleife im zweiten Teil ausführen, da jede Wahrscheinlichkeit besteht, dass twoway individuell sein muss.

Es gibt jedoch einen Kompromiss: Aufgrund der while-Schleife im ersten Abschnitt und der Rekursion in der return-Anweisung garantiert diese Funktion nicht die Ausführungszeit, sie ist tatsächlich nicht effektiv.

Ergebnis

Ich habe einen einfachen Test gemacht, um die Verteilung meiner Antwort zu beobachten.

result = [ Rand7() for x in xrange(777777) ]

ans = {
    1: 0,
    2: 0,
    3: 0,
    4: 0,
    5: 0,
    6: 0,
    7: 0,
}

for i in result:
    ans[i] += 1

print ans

Es gab

{1: 111170, 2: 110693, 3: 110651, 4: 111260, 5: 111197, 6: 111502, 7: 111304}

Daher können wir wissen, dass diese Antwort in einer Normalverteilung liegt.

Vereinfachte Antwort

Wenn Sie sich nicht für die Ausführungszeit dieser Funktion interessieren, finden Sie hier eine vereinfachte Antwort, die auf der obigen Antwort basiert, die ich gegeben habe:

def Rand7():
    ans = Rand5() + (Rand5()-1) * 5
    return ans if ans < 8 else Rand7()

Dies erhöht die Wertwahrscheinlichkeit, die größer als 8 ist, aber wahrscheinlich die kürzeste Antwort auf dieses Problem ist.

0
Colin Su

Ähnlich wie Martins Antwort , wendet die Entropie jedoch viel seltener weg:

int Rand7(void) {
  static int m = 1;
  static int r = 0;

  for (;;) {
    while (m <= INT_MAX / 5) {
      r = r + m * (Rand5() - 1);
      m = m * 5;
    }
    int q = m / 7;
    if (r < q * 7) {
      int i = r % 7;
      r = r / 7;
      m = q;
      return i + 1;
    }
    r = r - q * 7;
    m = m - q * 7;
  }
}

Hier bauen wir einen zufälligen Wert zwischen 0 und m-1 auf und versuchen, m zu maximieren, indem Sie so viele Zustände hinzufügen, wie ohne Überlauf passen (INT_MAX ist der größte Wert, der in int in C passt, oder Sie können ihn durch einen beliebigen großen ersetzen Wert, der in Ihrer Sprache und Architektur Sinn macht).

Dann; Wenn r in das größtmögliche Intervall fällt, das gleichmäßig durch 7 teilbar ist, enthält es ein praktikables Ergebnis, und wir können dieses Intervall durch 7 dividieren und den Rest als unser Ergebnis nehmen und den Rest des Werts unserem Entropiepool zurückgeben. Ansonsten ist r in dem anderen Intervall, das sich nicht gleichmäßig teilt, und wir müssen unseren Entropiepool aus diesem schlecht passenden Intervall verwerfen und erneut starten.

Verglichen mit den populären Antworten hier, wird Rand5() im Durchschnitt etwa halb so oft genannt.

Die Unterteilungen können in triviale Bit-Twiddles und LUTs für die Leistung herausgerechnet werden.

0
sh1

Dieser Ausdruck reicht aus, um zufällige Ganzzahlen zwischen 1 und 7 zu erhalten

int j = ( Rand5()*2 + 4 ) % 7 + 1;
0
user2713461

Dieser Algorithmus reduziert die Anzahl der Aufrufe von Rand5 auf das theoretische Minimum von 7/5. Rufe ihn 7 mal an, indem du die nächsten 5 Rand7-Nummern produzierst.

Es gibt keine Zurückweisung eines Zufallsbits und es gibt KEINE Möglichkeit, das Ergebnis immer zu warten.

#!/usr/bin/env Ruby

# random integer from 1 to 5
def Rand5
    STDERR.putc '.'
    1 + Rand( 5 )
end

@bucket = 0
@bucket_size = 0

# random integer from 1 to 7
def Rand7
    if @bucket_size == 0
        @bucket = 7.times.collect{ |d| Rand5 * 5**d }.reduce( &:+ )
        @bucket_size = 5
    end

    next_Rand7 = @bucket%7 + 1

    @bucket      /= 7
    @bucket_size -= 1

    return next_Rand7
end

35.times.each{ putc Rand7.to_s }
0
robermorales

Hier ist eine Lösung, die versucht, die Anzahl der Aufrufe von Rand5 () zu minimieren, während die Implementierung einfach und effizient bleibt. Insbesondere sind im Gegensatz zu Adam Rosenfields zweiter Antwort keine willkürlichen großen ganzen Zahlen erforderlich. Es wird die Tatsache ausgenutzt, dass 23/19 = 1.21052 ... eine gute rationale Annäherung an log (7)/log (5) = 1.20906 ... ist, sodass wir 19 zufällige Elemente von {1, ..., 7 erzeugen können } aus 23 zufälligen Elementen von {1, ..., 5} durch Zurückweisungsabtastung mit nur einer geringen Zurückweisungswahrscheinlichkeit. Im Durchschnitt benötigt der unten stehende Algorithmus ungefähr 1.266 Aufrufe von Rand5 () für jeden Aufruf von Rand7 (). Wenn die Verteilung von Rand5 () gleichmäßig ist, ist es auch Rand7 ().

uint_fast64_t pool;

int capacity = 0;

void new_batch (void)
{
  uint_fast64_t r;
  int i;

  do {
    r = 0;
    for (i = 0; i < 23; i++)
      r = 5 * r + (Rand5() - 1);
  } while (r >= 11398895185373143ULL);  /* 7**19, a bit less than 5**23 */

  pool = r;
  capacity = 19;
}

int Rand7 (void)
{
  int r;

  if (capacity == 0)
    new_batch();

  r = pool % 7;
  pool /= 7;
  capacity--;

  return r + 1;
}
0
Emil Jeřábek