Rand5 () a Rand7 () [chiuso]


29

Viene fornita una funzione Rand5 (). Questa funzione restituisce numeri interi perfettamente casuali (distribuzione uguale) tra 1 e 5.

Fornire la funzione Rand7 (), che utilizza Rand5 () per produrre numeri interi perfettamente casuali tra 1 e 7.




1 e 5 inclusi? cioè dal set {1,2,3,4,5}?
Aaron McDaid l'

1
Quali criteri determinano un singolo vincitore?
Kojiro,

Quel momento in cui ti rendi conto che questa è in realtà una vecchia domanda.
nyuszika7h

Risposte:


11

Java - 61 caratteri

int rand7(){int s=0,c=7;while(c-->0)s+=rand5();return s%7+1;}

Driver di test per la convalida:

class Rand {

    public static void main(String[] args) {
        int[] nums = new int[7];
        // get a lot of numbers
        for(int i = 0; i < 10000000; i++) nums[rand7()-1]++;
        // print the results
        for(int i = 0; i < 7; i++) System.out.println((i+1) + ": " + nums[i]);
    }

    // just for rand5()
    static java.util.Random r = new java.util.Random();

    static int rand5() {
        return r.nextInt(5)+1; // Random.nextInt(n) returns 0..n-1, so add 1
    }

    static int rand7(){int s=0,c=7;while(c-->0)s+=rand5();return s%7+1;}

}

risultati

C:\Documents and Settings\glowcoder\My Documents>java Rand
1: 1429828
2: 1429347
3: 1428328
4: 1426486
5: 1426784
6: 1429853
7: 1429374

C:\Documents and Settings\glowcoder\My Documents>

10
Punti extra per "va all'operatore"
Steve P

radere un salmerino? int rand7 () {for (int s = 0, c = 7; c -> 0; s + = rand5 ()); return s% 7 + 1;}
Ron

3
Questa risposta non è corretta: le probabilità di questa funzione che restituiscono i valori da 1 a 7 sono rispettivamente 0,1430656, 0,1430016, 0,1428224, 0,1426432, 0,1426432, 0,1428224 e 0,1430016. Sì, la differenza tra le probabilità minima e massima è inferiore a 0.0005, ma la domanda specificava "numeri interi perfettamente casuali".
Ilmari Karonen,

@ilmari Hai ragione - Ho appena eseguito un test e sembra che la distribuzione non sia nemmeno ... fammi pensare su questo ...
corsiKa

1
@userunknown: Sì, le probabilità che ho pubblicato in realtà non sono approssimazioni, ma esatte (0,1430656 = 11177/78125, ecc.) assumendo un carattere perfettamente casuale rand5. Li ho calcolati in Maple usando una semplice algebra a matrice, ma puoi farlo con carta e matita in pochi minuti se vuoi. Ad ogni modo, risulta che Omar ha già pubblicato le stesse cifre (senza fattore di normalizzazione) in un commento a un'altra risposta un paio di giorni prima. (Anche ps., Puoi solo @notificare un utente per commento, anche se l'autore del post viene sempre avvisato.)
Ilmari Karonen

7

Perl - 47 (erano 52) caratteri

sub rand7{($x=5*&rand5+&rand5-3)<24?int($x/3):&rand7} 

Inoltre uso l'operatore ternario E la ricorsione. Miglior giorno di sempre!

OK, 47 caratteri se usi mod invece di div:

sub rand7{($x=5*&rand5+&rand5)<27?$x%7+1:&rand7} 

Così vicino ... sostituisci il 30 con 27 (= 6 + 21) e otterrai una distribuzione perfettamente uniforme. Oh, e puoi rilasciare gli ultimi due &segni per ridurlo a 46 caratteri (incluso lo spazio, che porta la tua versione attuale a 48).
Ilmari Karonen,

7

JavaScript, 42

Rand7=f=_=>(x=Rand5()+Rand5()*5-5)>7?f():x

Bonus ES5:

Rand7=eval.bind(0,'for(;x=Rand5()+Rand5()*5-5,x>7;);x')

6

Ruby - 54 caratteri (basato sulla soluzione Dan McGrath, usando loop)

def rand7;x=8;while x>7 do x=rand5+5*rand5-5 end;x;end

Ruby - 45 caratteri (stessa soluzione, usando la ricorsione)

def rand7;x=rand5+5*rand5-5;x>7 ?rand7: x;end

Può essere ridotto di 1 carattere usando (x=rand5+5*rand5-5)>7?.
Lars Haugseth,

5

In Python:

def Rand7():
  while True:
    x = (Rand5() - 1) * 5 + (Rand5() - 1)
    if x < 21: return x/3 + 1

4

In Common Lisp 70 caratteri:

(defun rand7()(let((n(-(+(rand5)(* 5(rand5)))5)))(if(> n 7)(rand7)n)))

La parentesi occupa più spazio di quanto vorrei.


Bello. Puoi spremere altri due personaggi creando una variabile globale:(defun rand7()(setq n(-(+(rand5)(* 5(rand5)))5))(if(> n 7)(rand7)n))
Dr. Pain

Ancora meglio:(defun rand7()(if(>(setq n(-(+(rand5)(* 5(rand5)))5))7)(rand7)n))
Dr. Pain,

4

In c / c ++ usando il campionamento del rifiuto

int rand7(){int x=8;while(x>7)x=rand5()+5*rand5()-5;return x;}

62 caratteri.


@barrycarter: la condizione è while(x>7), quindi sarebbe soddisfatta solo dai numeri nell'intervallo valido.
mellamokb,

Colpa mia. Cancella il mio stupido commento.
Barrycarter,

@barry E poi ne hai lasciato un altro. ;)
Mateen Ulhaq,

Mi ci sono voluti alcuni minuti per capire come la matematica qui produce una distribuzione uniformemente casuale che può essere utilizzata per il campionamento del rifiuto.
Daniel,

3

Traduzione in PHP, dalla risposta pubblicata da Dan McGrath.

function Rand7(){$x=8;while($x>7)$x=rand5()+5*rand5()-5;return $x;}

67 caratteri.


Questo non dovrebbe essere preceduto dalla parola "funzione" (e da uno spazio)?
jtjacques,

Sì ... e ora sono 67 personaggi ...
Marc-François

3

R, 34 caratteri

In R (un linguaggio costruito per il calcolo statistico), una soluzione deliberatamente imbroglione:

# Construct a Rand5 function
Rand5 <- function() sample(seq(5),1)
# And the golf
Rand7=function(r=Rand5())sample(1:(r/r+6),1)
# Or (same character count)
Rand7=function(r=Rand5())sample.int(r/r+6,1)
# Or even shorter(thanks to @Spacedman)
Rand7=function()sample(7)[Rand5()]

Grazie alla valutazione pigra degli argomenti, ho eliminato il punto e virgola e le parentesi graffe.

Output su 10 ^ 6 replicati:

> test <- replicate(10^6,Rand7())
> table(test)
test
     1      2      3      4      5      6      7 
142987 142547 143133 142719 142897 142869 142848 

library(ggplot2)
qplot(test)

istogramma dei risultati


2
Se stai per essere un imbroglione, potresti anche essere il miglior imbroglione che puoi essere:Rand7=function(){r=Rand5();sample(7)[r]}
Spacedman

Se hai intenzione di farlo, perché preoccuparsi della memoria intermedia? Rand7=function(){sample(7)[Rand5()]}
Brian Diggs,

@BrianDiggs Path-dependency in action .... :-)
Ari B. Friedman,

3

scala, 47, 40 59 caratteri:

def rand7:Int={val r=5*(rand5-1)+rand5
if(r<8)r else rand7}

con 2 ingressi da rand5:

\ 1 2 3 4 5 
1 1 2 3 4 5  
2 6 7 8 ..
3 11 ..
4 ..
5

Moltiplico il primo-1 per 5 e aggiungo il secondo. La maggior parte dei risultati vengono ignorati e portano a un nuovo calcolo. Il risultato dovrebbe essere una distribuzione uguale dei valori da 1-25, da cui scelgo solo i primi 7. Potrei accettare i primi 21 con la costruzione di un modulo, ma questo porterebbe a un codice più lungo.

codice storico che ha fallito, ma non molto ovviamente. Grazie a Ilmari Karonen per averlo sottolineato:

def rand7=(1 to 7).map(_=>rand5).sum%7+1

Grazie a Yoshiteru Takeshita, per questo approccio alla scala 2.8.0 che ha reso 'somma' così semplice. La mia soluzione prima:

def rand7=((0/:(1 to 7))((a,_)=>a+rand5-1))%7+1

rand5:

val rnd = util.Random 
def rand5 = rnd.nextInt (5) + 1


L'utente Yoshiteru Takeshita ha proposto una riduzione a 40 caratteri per Scala 2.8.0 o successive comedef rand7=(1 to 7).map(_=>rand5).sum%7+1
Peter Taylor,

Anche questa soluzione non è corretta, vedere i commenti alla risposta di glowcoder .
Ilmari Karonen,

@IlmariKaronen: Hai ragione - ho rielaborato la mia soluzione.
utente sconosciuto

3

C ++

int Rand4()
{
    int r = Rand5();
    return r > 4 ? Rand4() : r;
}

inline int Rand8()
{    
    return (Rand4() - 1) << 2 + Rand4();
}

int Rand7()
{
    int r = Rand8();
    return r > 7 ? Rand7() : r;
}

C ++ (109)

golfed

int Rand4(){int r=Rand5();return r>4?Rand4():r;}int Rand7(){int r=Rand4()-1<<2+Rand4();return r>7?Rand7():r;}

Non credo davvero che tu possa chiamarlo "un solo liner" perché i punti e virgola definiscono una riga di codice in C ++.
Peter Olson,

@Peter Oh beh, non richiede più nemmeno una linea.
Mateen Ulhaq,


2

Traduzione in Javascript, dalla risposta pubblicata da Dan McGrath.

function Rand7(){x=8;while(x>7)x=rand5()+5*rand5()-5;return x}

62 caratteri


1
function Rand7(){for(x=8;x>7;x=rand5()+5*rand5()-5);return x}è un po 'più breve: P
JiminP

2

JavaScript, 85

function Rand7(){for(x=0,i=1;i<8;x^=i*((k=Rand5())%2),i*=1+(k<5));return x?x:Rand7()}

So che c'è una risposta più breve, ma volevo mostrare il test di questo enigma. Si scopre che solo la risposta di Clyde Lobo utilizzando il campionamento del rifiuto di Dan McGrath è corretta (tra le risposte di JS).


2

С ++

int Rand7()
{
    int r = Rand5();
    int n = 5;
    do {
        r = (r - 1) * 5 + Rand5();
        int m = n * 5 / 7 * 7;
        if (r <= m) {
            return r % 7 + 1;
        }
        r -= m;
        n = n * 5 - m;
    } while (1);
}

Distribuzione numerica (1000000 numeri interi):

142935 142751 142652 143299 142969 142691 142703

Il numero medio di chiamate a Rand5 () per ogni numero intero generato è di circa 2,2 (da 2 a 10+).

1 2      3      4     5    6   7 8  9 10
0 840180 112222 44433 2212 886 0 60 6 1

2

In Java (o C / C ++ suppongo)

  • usando la formula di generazione di Alexandru, in 65 caratteri:

    int rand7(){int x=rand5()*5+rand5()-6;return x>20?rand7():x/3+1;}
    
  • usando la formula di generazione di Dan McGrath, in 60 caratteri

    int rand7(){int x=rand5()+5*rand5()-5;return x>7?rand7():x;}
    

1

Clojure - 58 caratteri

(defn rand7[](#(if(<% 8)%(rand7))(+(rand5)(*(rand5)5)-5)))

1

Python, 56 37 caratteri

Un'altra soluzione che potrebbe essere sbagliata, in Python:

rand7 = lambda: sum(rand5() for i in range(7)) % 7 + 1

Questo sembra essere troppo semplice, ma quando provo:

counter = [0] * 7
for i in range(100000):
     counter[rand7()] += 1

Ottengo una distribuzione ragionevolmente uniforme (tra 14000 e 14500).

Bene, ora come qualcuno ha votato per questo post: questa soluzione è davvero corretta? Ho più pubblicato questo qui per far criticare le persone. Bene, se è corretto, la mia versione golfata sarebbe:

rand7=lambda:eval("+rand5()"*7)%7+1

che esce a 37 caratteri.


La tua soluzione non è corretta: basi la tua decisione su 7 tiri di un dado a 5 facce equo, il che significa che ci sono 5 ^ 7 (5 alla 7a potenza) risultati equipaggiabili. Poiché questo non è un multiplo di 7, non è possibile restituire 7 risultati equiprobabili. Non credo che ci sia una formula semplice per quello che ritorni; puoi forzare bruscamente il calcolo o elaborarlo manualmente su numeri più piccoli (lancia 3 monete (H = 1, T = 2) e somma i risultati).
Gilles 'SO- smetti di essere malvagio' il

1
Wow, la distribuzione che generi, sebbene non uniforme, è notevolmente vicina: la proporzione esatta delle probabilità di ogni numero è {1: 11177, 2: 11172, 3: 11158, 4: 11144, 5: 11144, 6: 11158, 7: 11172}
Omar,


1

Python, 70 caratteri

def rand7():
 while True:
  n=5*(rand5()-1)+(rand5()-1)
  if n<21:return n%7+1

ma completamente corretto in base al ragionamento qui .


1

Perl, 43 caratteri, campionamento iterativo di rifiuto

sub rand7{1while($_=5*&rand5-rand5)>6;$_+1}

Questo dà un avvertimento Ambiguous use of -rand5 resolved as -&rand5(), ma funziona correttamente. Preparare un &anche alla seconda rand5chiamata lo risolve al costo di un colpo. (Viceversa, l'altro &può anche essere rimosso se rand5 è stato definito con un ()prototipo.)

Ps. La seguente versione a 46 caratteri è circa tre volte più veloce:

sub rand7{1while($_=5*&rand5-rand5)>20;$_%7+1}

1

Java - 66 caratteri

int rand7(){int s;while((s=rand5()*5+rand5())<10);return(s%7+1);}

Più lungo della routine precedente, ma penso che questo ritorni numeri distribuiti uniformemente in meno tempo.


1

PostScript (46)

Questo utilizza la codifica del token binario, quindi ecco un hexdump:

00000000  2f 72 61 6e 64 37 7b 38  7b 92 38 37 92 61 7b 92  |/rand7{8{.87.a{.|
00000010  40 7d 69 66 92 75 32 7b  72 61 6e 64 35 7d 92 83  |@}if.u2{rand5}..|
00000020  35 92 6c 92 01 35 92 a9  7d 92 65 7d 92 33        |5.l..5..}.e}.3|
0000002e

Per provarlo, puoi anche scaricarlo .

Ecco il codice non modificato e commentato, insieme al codice di prova.

% This is the actual rand7 procedure.
/rand7{
  8{                      % potentialResult
    % only if the random number is less than or equal to 7, we're done
    dup 7 le{             % result
      exit                % result
    }if                   % potentialResult
    pop                   % -/-
    2{rand5}repeat        % randomNumber1 randomNumber2
    5 mul add 5 sub       % randomNumber1 + 5*randomNumber2 - 5 = potentialResult
  }loop
}def

%Now, some testing code.

% For testing, we use the built-in rand operator; 
% Doesn't really give a 100% even distribution as it returns numbers
% from 0 to 2^31-1, which is of course not divisible by 5.
/rand5 {
  rand 5 mod 1 add
}def

% For testing, we initialize a dict that counts the number of times any number
% has been returned. Of course, we start the count at 0 for every number.
<<1 1 7{0}for>>begin

% Now we're calling the function quite a number of times 
% and increment the counters accordingly.
1000000 {
  rand7 dup load 1 add def
}repeat

% Print the results
currentdict{
  2 array astore ==
}forall

-1
int result = 0;

for (int i = 0; i++; i<7)
    if (((rand(5) + rand(5)) % 2) //check if odd
        result += 1;

return result + 1;

2
Questo non darà una distribuzione uniforme. Guarda la distribuzione di rand (5) + rand (5) su oltre 10000 iterazioni per capire perché
gnibbler

il risultato può essere qualsiasi numero compreso tra 1 e 8 nel tuo codice ...
Omar,

Inoltre, come diceva gnibbler, la distribuzione non è uniforme: (rand (5) + rand (5))% 2 è distorto verso 0, produce 0 13 volte ogni 12 volte produce 1; cioè, le probabilità sono proporzionali a {0: 13, 1: 12}. Con questa notazione, le propensioni per la tua funzione sono proporzionali a {1: 62748517, 2: 405451956, 3: 1122790032, 4: 1727369280, 5: 1594494720, 6: 883104768, 7: 271724544, 8: 35831808} (abbastanza pesantemente inclinato verso numeri più grandi). Oppure, correggendo il ciclo per eseguire 6 volte, {1: 4826809, 2: 26733096, 3: 61691760, 4: 75928320, 5: 52565760, 6: 19408896, 7: 2985984}
Omar,

-1

R (30 caratteri)

Definisci rand7:

rand7=function(n)sample(7,n,T)

Poiché R è stato scritto pensando all'analisi statistica, questo compito è banale e utilizzo la funzione integrata samplecon la sostituzione impostata su TRUE.

Uscita campione:

> rand7(20)
 [1] 4 3 6 1 2 4 3 2 3 2 5 1 4 6 4 2 4 6 6 1
> rand7(20)
 [1] 1 2 5 2 6 4 6 1 7 1 1 3 7 6 4 7 4 2 1 2
> rand7(20)
 [1] 6 7 1 3 3 1 5 4 3 4 2 1 5 4 4 4 7 7 1 5

1
Dice che devi usare Rand5. Non dice come, ma devi usarlo ...
Spacedman

@Spacedman Sì, l'ho ignorato esplicitamente. Questo è l'uso per non riferimento.
Andrie,

-1

Groovy

rand7={if(b==null)b=rand5();(b=(rand5()+b)%7+1)}

distribuzione di esempio oltre 35.000 iterazioni:

[1:5030, 2:4909, 3:5017, 4:4942, 5:5118, 6:4956, 7:5028]

È brutto che sia stato?



-1

Cosa ne pensi di questo?

int Rand7()
{
    return Rand5()+ Rand5()/2;
}

Qualunque sia la lingua, il suo /operatore fa matematica intera? Cosa succede ai tuoi risultati se esegue calcoli decimali, a virgola mobile o interi?
Kojiro,

Supponendo divisione intera, questa funzione ha la seguente distribuzione: [2/25, 4/25, 5/25, 5/25, 5/25, 3/25, 1/25]. Non esattamente uniforme.
primo

primo ha ragione. l'aggiunta di numeri casuali generalmente inclina le probabilità verso i valori medi.
Gnibbler,

-1

Java - 54

int m=0;int rand7(){return(m=m*5&-1>>>1|rand5())%7+1;}

Test di distribuzione: [1000915, 999689, 999169, 998227, 1001653, 1000419, 999928]

Algoritmo:

  • Mantieni una variabile globale
  • moltiplicare per 5, in modo da ottenere 5 posti liberi alla fine meno significativa
  • Troncare il bit del segno per renderlo positivo (non necessario se erano supportati numeri senza segno)
  • Modulo 7 è la risposta

> I numeri non sono più reciprocamente non correlati, ma individualmente perfettamente casuali.


-1

Rubino (43 byte)

def rand7;(0..7).reduce{|i|i+rand5}%7+1;end

La soluzione di cemper93 portata su Ruby è più corta di tre byte;) (34 byte)

def rand7;eval("+rand5"*7)%7+1;end

-3

Codice C / C ++ il codice core ha una sola riga!

static unsigned int gi = 0;

int rand7()
{
    return (((rand() % 5 + 1) + (gi++ % 7)) % 7) + 1;
}

//call this seed before rand7
//maybe it's not best seed, if yo have any good idea tell me please
//and thanks JiminP again, he remind me to do this
void srand7()
{
    int i, n = time(0);
    for (i = 0; i < n % 7; i++)
        rand7();
}

Srand7 () è il seme di rand7, deve chiamare questa funzione prima di rand7, proprio come chiama srand prima di rand in C.

Questo è molto buono, perché chiama rand () solo una volta, e niente loop, niente spese extra.

Lascia che ti spieghi: considera un array intero con dimensione 5:

1st get one number from 1 2 3 4 5 by rand5
2nd get one number from 2 3 4 5 6
3rd get one number from 3 4 5 6 7
4th get one number from 4 5 6 7 1
5th get one number from 5 6 7 1 2
5th get one number from 6 7 1 2 3
7th get one number from 7 1 2 3 4

Quindi abbiamo la TABELLA, ognuna di 1-7 appare 5 volte in essa e ha tutti i 35 numeri, quindi la probabilità di ogni numero è 5/35 = 1/7. E la prossima volta,

8th get one number from 1 2 3 4 5
9th get one number from 2 3 4 5 6
......

Dopo un tempo sufficiente, possiamo ottenere la distribuzione uniforme di 1-7.

Quindi, possiamo allocare un array per ripristinare i cinque elementi di 1-7 mediante loop-left-shift e ottenere un numero ogni volta da array di rand5. Invece, possiamo generare tutte e sette le matrici prima e usarle in modo circolare. Il codice è anche semplice, ha molti codici funzione in grado di farlo.

Ma possiamo usare le proprietà dell'operazione%, quindi la tabella 1-7 righe è equivalente a (rand5 + i)% 7, ovvero: a = rand ()% 5 + 1 è rand5 in linguaggio C, b = gi ++ % 7 genera tutte le permutazioni nella tabella sopra e 0 - 6 sostituisce 1 - 7 c = (a + b)% 7 + 1, genera 1 - 7 in modo uniforme. Finalmente abbiamo ottenuto questo codice:

(((rand() % 5 + 1) + (gi++ % 7)) % 7) + 1 

Tuttavia, non possiamo ottenere 6 e 7 alla prima chiamata, quindi abbiamo bisogno di un seed, alcuni come srand for rand in C / C ++, per confondere la permutazione per la prima chiamata formale.

Ecco il codice completo per i test:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

static unsigned int gi = 0;

//a = rand() % 5 + 1 is rand5 in C language,
//b = gi++ % 7 generates all permutations,
//c = (a + b) % 7 + 1, generates 1 - 7 uniformly.
//Dont forget call srand7 before rand7
int rand7()
{
   return (((rand() % 5 + 1) + (gi++ % 7)) % 7) + 1;
}

//call this seed before rand7
//maybe it's not best seed, if yo have any good idea tell me please
//and thanks JiminP again, he remind me to do this
void srand7()
{
    int i, n = time(0);
    for (i = 0; i < n % 7; i++)
        rand7();
}

void main(void)
{
    unsigned int result[10] = {0};
    int k;

    srand((unsigned int)time(0)); //initialize the seed for rand
    srand7() //initialize the rand7

    for (k = 0; k < 100000; k++)
        result[rand7() - 1]++;

    for (k = 0; k < 7; k++)
        printf("%d : %.05f\n", k + 1, (float)result[k]/100000);
}

"Supera" il "test", ma ciò non significa che questa sia una buona funzione casuale. Posso ottenere 6o 7chiamandolo una volta ?
JiminP

Ma ci sono buoni tipi e cattivi tipi di approssimazione. E questo codice è negativo, perché non fornisce una distribuzione uniforme quando viene chiamato una sola volta. Se uno ha scritto qualcosa del genere int main(){if(rand7()==6) printf("Hello, world!");}, l'approssimazione usando il ciclo stamperà "Ciao, mondo!" 1 su 7 volte, ma il tuo codice no.
JiminP

grazie @JiminP! hai ragione per 6,7 alla prima volta. ho bisogno che un seme si disgreghi prima di chiamare rand7, il seme proprio come lo srand in C / C ++. ho corretto il mio codice e grazie ancora !!!
Sean,

hm .... lo srand10 non funziona, gli ultimi 3 numeri non possono ottenere a 10, 20, 30 ... posizioni. scusa @JiminP, ma come modificarlo? penso che questo sia un modo pieno di speranza.
Sean,

2
Diverse chiamate a questa funzione non sono indipendenti l'una dall'altra. Le specifiche qui non richiedono questo, ma questo è in genere previsto dai generatori di numeri casuali. Altrimenti, potresti dire, restituisci un numero uniforme casuale la prima volta e nelle chiamate future restituisci (precedente + 1)% 7 ...
Omar,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.