Se le proporciona una función Rand5 (). Esta función devuelve enteros perfectamente aleatorios (distribución igual) entre 1 y 5.
Proporcione la función Rand7 (), que usa Rand5 () para producir enteros perfectamente aleatorios entre 1 y 7.
Se le proporciona una función Rand5 (). Esta función devuelve enteros perfectamente aleatorios (distribución igual) entre 1 y 5.
Proporcione la función Rand7 (), que usa Rand5 () para producir enteros perfectamente aleatorios entre 1 y 7.
Respuestas:
Java - 61 caracteres
int rand7(){int s=0,c=7;while(c-->0)s+=rand5();return s%7+1;}
Controlador de prueba para validación:
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;}
}
Resultados
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
. Los calculé en Maple usando álgebra matricial simple, pero puede hacerlo con lápiz y papel en unos minutos si lo desea. De todos modos, resulta que Omar ya publicó las mismas cifras (sin factor de normalización) en un comentario a otra respuesta un par de días antes. (También ps., Solo puede @ notificar a un usuario por comentario, aunque el autor de la publicación siempre se notifica en cualquier caso.)
sub rand7{($x=5*&rand5+&rand5-3)<24?int($x/3):&rand7}
Además, puedo usar el operador ternario Y la recursividad. ¡El mejor día!
OK, 47 caracteres si usas mod en lugar de div:
sub rand7{($x=5*&rand5+&rand5)<27?$x%7+1:&rand7}
&
signos para reducirlo a 46 caracteres (incluido el espacio, que pone su versión actual en 48).
Ruby - 54 caracteres (basado en la solución de Dan McGrath, usando el bucle)
def rand7;x=8;while x>7 do x=rand5+5*rand5-5 end;x;end
Ruby - 45 caracteres (misma solución, usando recursividad)
def rand7;x=rand5+5*rand5-5;x>7 ?rand7: x;end
(x=rand5+5*rand5-5)>7?
.
En Common Lisp 70 caracteres:
(defun rand7()(let((n(-(+(rand5)(* 5(rand5)))5)))(if(> n 7)(rand7)n)))
Los paréntesis ocupan más espacio del que quisiera.
(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))
En c / c ++ usando muestreo de rechazo
int rand7(){int x=8;while(x>7)x=rand5()+5*rand5()-5;return x;}
62 caracteres.
while(x>7)
, por lo que solo se cumpliría con números en el rango válido.
Traducción a PHP, de la respuesta publicada ny Dan McGrath.
function Rand7(){$x=8;while($x>7)$x=rand5()+5*rand5()-5;return $x;}
67 caracteres.
En R (un lenguaje creado para el cálculo estadístico), una solución deliberadamente engañosa:
# 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()]
Gracias a la evaluación perezosa de los argumentos, eliminé el punto y coma y las llaves.
Salida sobre 10 ^ 6 réplicas:
> 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 entradas de rand5:
\ 1 2 3 4 5
1 1 2 3 4 5
2 6 7 8 ..
3 11 ..
4 ..
5
Multiplico el primer 1 por 5 y agrego el segundo. La mayoría de los resultados se ignoran y conducen a un nuevo cálculo. El resultado debería ser una distribución equitativa de valores de 1 a 25, de los cuales solo selecciono los primeros 7. Podría aceptar los primeros 21 con la construcción de un módulo, pero esto conduciría a un código más largo.
código histórico que falló, pero no muy obviamente. Gracias a Ilmari Karonen por señalarlo:
def rand7=(1 to 7).map(_=>rand5).sum%7+1
Gracias a Yoshiteru Takeshita, por este enfoque scala-2.8.0 que hizo que la 'suma' fuera tan fácil. Mi solución antes:
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;}
Traducción a Javascript, de la respuesta publicada por Dan McGrath.
function Rand7(){x=8;while(x>7)x=rand5()+5*rand5()-5;return x}
62 caracteres
function Rand7(){for(x=8;x>7;x=rand5()+5*rand5()-5);return x}
es un poco más corto: P
function Rand7(){for(x=0,i=1;i<8;x^=i*((k=Rand5())%2),i*=1+(k<5));return x?x:Rand7()}
Sé que hay una respuesta más corta, pero quería mostrar la prueba de este rompecabezas. Resulta que solo la respuesta de Clyde Lobo usando el muestreo de rechazo de Dan McGrath es correcta (entre las respuestas de 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);
}
Distribución de números (1000000 enteros):
142935 142751 142652 143299 142969 142691 142703
El número promedio de llamadas a Rand5 () por cada número entero generado es de aproximadamente 2.2 (2 a 10+).
1 2 3 4 5 6 7 8 9 10
0 840180 112222 44433 2212 886 0 60 6 1
En Java (o C / C ++, supongo)
usando la fórmula de generación de Alexandru, en 65 caracteres:
int rand7(){int x=rand5()*5+rand5()-6;return x>20?rand7():x/3+1;}
usando la fórmula de generación de Dan McGrath, en 60 caracteres
int rand7(){int x=rand5()+5*rand5()-5;return x>7?rand7():x;}
Otra solución que puede estar mal, en Python:
rand7 = lambda: sum(rand5() for i in range(7)) % 7 + 1
Esto parece ser demasiado simple, pero cuando lo intento:
counter = [0] * 7
for i in range(100000):
counter[rand7()] += 1
Obtengo una distribución razonablemente uniforme (todo entre 14000 y 14500).
Bien, ahora que alguien votó por esta publicación: ¿Es esta solución realmente correcta? Más publiqué esto aquí para que la gente lo critique. Bueno, si es correcto, mi versión de golf sería:
rand7=lambda:eval("+rand5()"*7)%7+1
que sale a 37 caracteres.
Java, 65 caracteres:
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
pero completamente correcto basado en el razonamiento aquí .
sub rand7{1while($_=5*&rand5-rand5)>6;$_+1}
Esto da una advertencia Ambiguous use of -rand5 resolved as -&rand5()
, pero funciona correctamente. Anteponer un &
también a la segunda rand5
llamada lo corrige a costa de un golpe. (Por el contrario, el otro &
también se puede eliminar si rand5
se ha definido con un ()
prototipo).
PD. La siguiente versión de 46 caracteres es aproximadamente tres veces más rápida:
sub rand7{1while($_=5*&rand5-rand5)>20;$_%7+1}
int rand7(){int s;while((s=rand5()*5+rand5())<10);return(s%7+1);}
Más tiempo que la rutina anterior, pero creo que este devuelve números distribuidos uniformemente en menos tiempo.
PostScript (46)
Esto usa codificación de token binario, por lo tanto, aquí hay 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
Para probarlo, también puedes descargarlo .
Aquí está el código no comentado y comentado, junto con el código de prueba.
% 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;
Definir rand7:
rand7=function(n)sample(7,n,T)
Debido a que R fue escrito con el análisis estadístico en mente, esta tarea es trivial, y uso la función incorporada sample
con el reemplazo establecido en TRUE.
Salida de muestra:
> 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
Rand7=Rand5[]~Sum~{7}~Mod~7+1&
¿Qué tal esto?
int Rand7()
{
return Rand5()+ Rand5()/2;
}
/
operador matemática entera? ¿Qué sucede con sus resultados si hace matemática decimal, de coma flotante o de enteros?
[2/25, 4/25, 5/25, 5/25, 5/25, 3/25, 1/25]
. No exactamente uniforme.
int m=0;int rand7(){return(m=m*5&-1>>>1|rand5())%7+1;}
Prueba de distribución:
[1000915, 999689, 999169, 998227, 1001653, 1000419, 999928]
Algoritmo:
> Los números ya no están mutuamente no correlacionados, sino individualmente perfectamente al azar.
Código C / C ++ ¡el código central tiene una sola línea!
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();
}
El srand7 () es la semilla de rand7, debe llamar a esta función antes que rand7, al igual que call srand antes de rand en C.
Esta es una muy buena, porque llama a rand () solo una vez, y no tiene bucle, no gasta recuerdos adicionales.
Permítame explicarlo: considere una matriz entera con un tamaño de 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
Entonces obtuvimos la TABLA, cada uno de 1-7 aparece 5 veces en ella y tiene los 35 números, por lo que la probabilidad de cada número es 5/35 = 1/7. Y la próxima vez
8th get one number from 1 2 3 4 5
9th get one number from 2 3 4 5 6
......
Después de suficientes tiempos, podemos obtener la distribución uniforme de 1-7.
Entonces, podemos asignar una matriz para restaurar los cinco elementos de 1-7 por loop-left-shift, y obtener un número de la matriz cada vez por rand5. En cambio, podemos generar las siete matrices antes y usarlas circularmente. El código también es simple, tiene muchos códigos cortos que pueden hacer esto.
Pero podemos usar las propiedades de% operation, por lo que la tabla 1-7 filas es equivalente a (rand5 + i)% 7, es decir: a = rand ()% 5 + 1 es rand5 en lenguaje C, b = gi ++ % 7 genera todas las permutaciones en la tabla anterior, y 0 - 6 reemplaza 1 - 7 c = (a + b)% 7 + 1, genera 1 - 7 de manera uniforme. Finalmente, tenemos este código:
(((rand() % 5 + 1) + (gi++ % 7)) % 7) + 1
Pero, no podemos obtener 6 y 7 en la primera llamada, por lo que necesitamos una semilla, algunos como srand for rand en C / C ++, para desarmar la permutación para la primera llamada formal.
Aquí está el código completo para probar:
#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
llamándolo una vez ?
int main(){if(rand7()==6) printf("Hello, world!");}
, la aproximación usando el bucle imprimirá '¡Hola, mundo!' 1 de cada 7 veces, pero su código no.