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.
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.
Risposte:
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>
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.)
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}
&
segni per ridurlo a 46 caratteri (incluso lo spazio, che porta la tua versione attuale a 48).
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
(x=rand5+5*rand5-5)>7?
.
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.
(defun rand7()(setq n(-(+(rand5)(* 5(rand5)))5))(if(> n 7)(rand7)n))
(defun rand7()(if(>(setq n(-(+(rand5)(* 5(rand5)))5))7)(rand7)n))
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.
while(x>7)
, quindi sarebbe soddisfatta solo dai numeri nell'intervallo valido.
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.
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)
Rand7=function(){r=Rand5();sample(7)[r]}
Rand7=function(){sample(7)[Rand5()]}
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
def rand7=(1 to 7).map(_=>rand5).sum%7+1
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;
}
int Rand4(){int r=Rand5();return r>4?Rand4():r;}int Rand7(){int r=Rand4()-1<<2+Rand4();return r>7?Rand7():r;}
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
function Rand7(){for(x=8;x>7;x=rand5()+5*rand5()-5);return x}
è un po 'più breve: P
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).
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
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;}
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.
Java, 65 caratteri:
int rand7(){int r;do{r=rand5()+5*rand5()-5;}while(r>7);return r;}
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 .
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 rand5
chiamata 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}
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.
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
int result = 0;
for (int i = 0; i++; i<7)
if (((rand(5) + rand(5)) % 2) //check if odd
result += 1;
return result + 1;
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 sample
con 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
Cosa ne pensi di questo?
int Rand7()
{
return Rand5()+ Rand5()/2;
}
/
operatore fa matematica intera? Cosa succede ai tuoi risultati se esegue calcoli decimali, a virgola mobile o interi?
[2/25, 4/25, 5/25, 5/25, 5/25, 3/25, 1/25]
. Non esattamente uniforme.
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:
> I numeri non sono più reciprocamente non correlati, ma individualmente perfettamente casuali.
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);
}
6
o 7
chiamandolo una volta ?
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.