Rand5 () a Rand7 () [cerrado]


29

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.



8
Obligatorio xkcd: xkcd.com/221
Steven Rumbalski

1 y 5 inclusive? es decir, del conjunto {1,2,3,4,5}?
Aaron McDaid

1
¿Qué criterio determina un solo ganador?
kojiro

Ese momento cuando te das cuenta de que esta es realmente una vieja pregunta.
nyuszika7h

Respuestas:


11

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>

10
Puntos extra para el "va al operador"
Steve P

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

3
Esta respuesta no es correcta: las probabilidades de que esta función devuelva los valores del 1 al 7 son 0.1430656, 0.1430016, 0.1428224, 0.1426432, 0.1426432, 0.1428224 y 0.1430016 respectivamente. Sí, la diferencia entre las probabilidades mínimas y máximas es menor que 0.0005, pero aún así, la pregunta especificaba "enteros perfectamente aleatorios".
Ilmari Karonen

@ilmari Tienes razón - que acaba de ejecutar una prueba y parece que la distribución no es ni siquiera ... déjame pensar en eso ...
corsiKa

1
@userunknown: Sí, las probabilidades que publiqué en realidad no son aproximaciones, son exactas (0.1430656 = 11177/78125, etc.) suponiendo que son perfectamente aleatorias 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.)
Ilmari Karonen

7

Perl - 47 (antes 52) caracteres

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} 

Tan cerca ... reemplace el 30 con 27 (= 6 + 21) y obtendrá una distribución perfectamente uniforme. Ah, y puede soltar los dos últimos &signos para reducirlo a 46 caracteres (incluido el espacio, que pone su versión actual en 48).
Ilmari Karonen

7

JavaScript, 42

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

Bono ES5 cosa:

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

6

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

Se puede acortar en 1 char usando (x=rand5+5*rand5-5)>7?.
Lars Haugseth

5

En Python:

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

4

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.


Agradable. Puede exprimir dos caracteres más haciendo una variable global:(defun rand7()(setq n(-(+(rand5)(* 5(rand5)))5))(if(> n 7)(rand7)n))
Dr. Pain

Aún mejor:(defun rand7()(if(>(setq n(-(+(rand5)(* 5(rand5)))5))7)(rand7)n))
Dr. Pain

4

En c / c ++ usando muestreo de rechazo

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

62 caracteres.


@barrycarter: la condición es while(x>7), por lo que solo se cumpliría con números en el rango válido.
mellamokb

Mi error. Eliminé mi comentario tonto.
barrycarter

@barry Y luego dejaste otro. ;)
Mateen Ulhaq 05 de

Me llevó unos minutos darme cuenta de cómo las matemáticas aquí producen una distribución aleatoria uniforme que puede usarse para el muestreo de rechazo.
Daniel

3

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.


¿No debería estar precedido por la palabra "función" (y un espacio)?
jtjacques

Sí ... y ahora son 67 personajes ...
Marc-François

3

R, 34 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)

histograma de resultados


2
Si vas a ser tramposo, también puedes ser el mejor tramposo que puedas ser:Rand7=function(){r=Rand5();sample(7)[r]}
Spacedman

Si va a hacer eso, ¿por qué molestarse con el almacenamiento intermedio? Rand7=function(){sample(7)[Rand5()]}
Brian Diggs

@BrianDiggs Dependencia de ruta en acción ... :-)
Ari B. Friedman

3

scala, 47, 40 59 caracteres:

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


El usuario Yoshiteru Takeshita propuso una reducción a 40 caracteres para Scala 2.8.0 o posterior comodef rand7=(1 to 7).map(_=>rand5).sum%7+1
Peter Taylor

Esta solución tampoco es correcta, vea los comentarios a la respuesta de glowcoder .
Ilmari Karonen

@IlmariKaronen: Tienes razón: reelaboré mi solución.
Usuario desconocido

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;}

Realmente no creo que se pueda llamar a eso "un trazador de líneas" porque los punto y coma definen una línea de código en C ++.
Peter Olson

@ Peter Oh, bueno, ya ni siquiera requiere frases ingeniosas.
Mateen Ulhaq

Devolvió un número del 1 al 8.
jimmy23013

2

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


1
function Rand7(){for(x=8;x>7;x=rand5()+5*rand5()-5);return x}es un poco más corto: 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()}

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).


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);
}

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

2

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;}
    

1

Clojure - 58 caracteres

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

1

Python, 56 37 caracteres

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.


Su solución no es correcta: basa su decisión en 7 tiradas de un dado de 5 lados, lo que significa que hay 5 ^ 7 (5 a la 7ma potencia) resultados equiprobables. Como este no es un múltiplo de 7, no puede devolver 7 resultados equiprobables. No creo que haya una fórmula fácil para lo que devuelves; puede forzar el cálculo por fuerza bruta o calcularlo a mano en números más pequeños (lanzar 3 monedas (H = 1, T = 2) y sumar los resultados).
Gilles 'SO- deja de ser malvado'

1
Wow, la distribución que genera, aunque no es uniforme, es notablemente cercana: la proporción exacta de las probabilidades de cada número es {1: 11177, 2: 11172, 3: 11158, 4: 11144, 5: 11144, 6: 11158, 7: 11172}
Omar


1

Python, 70 caracteres

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í .


1

Perl, 43 caracteres, muestreo de rechazo iterativo

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 rand5llamada 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}

1

Java - 66 caracteres

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.


1

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

-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
Esto no dará una distribución uniforme. Vistazo a la distribución de rand (5) + rand (5) más de 10.000 iteraciones para ver por qué
gnibbler

el resultado puede ser cualquier número del 1 al 8 en su código ...
Omar

Además, como dijo gnibbler, la distribución no es uniforme: (rand (5) + rand (5))% 2 está sesgado hacia 0, produce 0 13 veces por cada 12 veces que produce 1; es decir, las probabilidades son proporcionales a {0: 13, 1: 12}. Con esa notación, las probalidades para su función son proporcionales a {1: 62748517, 2: 405451956, 3: 1122790032, 4: 1727369280, 5: 1594494720, 6: 883104768, 7: 271724544, 8: 35831808} (muy sesgada hacia números más grandes). O, arreglando el ciclo para que se ejecute 6 veces, {1: 4826809, 2: 26733096, 3: 61691760, 4: 75928320, 5: 52565760, 6: 19408896, 7: 2985984}
Omar

-1

R (30 caracteres)

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 samplecon 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

1
Dice que tienes que usar Rand5. No dice cómo, pero tienes que usarlo ...
Spacedman

@Spacedman Sí, lo ignoré explícitamente. Eso es uso por no referencia.
Andrie

-1

Maravilloso

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

distribución de ejemplo en más de 35,000 iteraciones:

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

¿Es malo que tenga estado?



-1

¿Qué tal esto?

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

Cualquiera que sea el idioma, ¿hace su /operador matemática entera? ¿Qué sucede con sus resultados si hace matemática decimal, de coma flotante o de enteros?
kojiro

Suponiendo división entera, esta función tiene la siguiente distribución: [2/25, 4/25, 5/25, 5/25, 5/25, 3/25, 1/25]. No exactamente uniforme.
primo

primo tiene razón. agregar números aleatorios generalmente sesgará las probabilidades hacia los valores medios.
gnibbler 01 de

-1

Java - 54

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:

  • Mantener una variable global
  • multiplique por 5, para obtener 5 lugares gratis en el extremo menos significativo
  • Truncar el bit de signo para que sea positivo (no es necesario si se admiten números sin signo)
  • Módulo 7 es la respuesta

> Los números ya no están mutuamente no correlacionados, sino individualmente perfectamente al azar.


-1

Rubí (43 bytes)

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

La solución de cemper93 portada a Ruby es tres bytes más corta;) (34 bytes)

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

-3

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);
}

'Pasa' la 'prueba', pero eso no significa que esta sea una buena función aleatoria. ¿Puedo obtenerlo 6o 7llamándolo una vez ?
JiminP

Pero hay buenos tipos y malos tipos de aproximación. Y este código es malo, porque no proporciona una distribución uniforme cuando se llama solo una vez. Si uno escribió algo así 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.
JiminP

gracias @JiminP! tienes razón para 6,7 ​​por primera vez. Necesito una semilla para desordenar antes de llamar a rand7, la semilla al igual que la srand en C / C ++. arreglé mi código, y gracias de nuevo !!!
Sean

hm .... el srand10 no funciona, los últimos 3 números no pueden llegar a 10, 20, 30 ... posiciones. lo siento @JiminP, pero ¿cómo modificarlo? Creo que esta es una forma esperanzadora.
Sean

2
Las diferentes llamadas a esta función no son independientes entre sí. La especificación aquí no requiere esto, pero eso es típicamente expecetd de generadores de números aleatorios. De lo contrario, podría decir, devuelva un número uniforme aleatorio la primera vez y en futuras llamadas simplemente devuelva (anterior + 1)% 7 ...
Omar
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.