Perl en Español

  1. Home
  2. Tutoriales
  3. Foro
  4. Artículos
  5. Donativos
  6. Publicidad
 
Índice general » Mundo Perl » Intermedio » Números aleatorios que siempre suman 1 Responder al tema
Nuevo tema


Página 1 de 1  [ 5 mensajes ] 
 
Nota Jue Jun 25, 2009 10:09 am
Avatar de Usuario
Perlero Nuevo
Registrado: Jue Jun 18, 2009 2:07 pm
Mensajes: 5
Números aleatorios que siempre suman 1
Hola amigos,

Estoy tratando de hacer una rutina que genere por vez un array de números aleatorios cuyos valores siempre sumen 1. Me explicaré mejor con un ejemplo:

Código:
DATO       NÚMERO
1              0.022
2              0.023
3              0.033
.               .
.               .
.               .
21            0.064
22            0.058
23            0.049
24            0.029
                ------
SUMA  ->   1.000


¿Alguien tiene alguna idea creativa de cómo hacer esto?

Saludos,

DW


Nota Jue Jun 25, 2009 10:32 am
Avatar de Usuario
Perlero Nuevo
Registrado: Jue Jun 18, 2009 2:07 pm
Mensajes: 5
Ok,

Olvidé decirles que ya tengo un código para esto, pero:

Citar:
"con perl hay siempre más de una forma de hacerlo"


Habrá muchas formas, claro está, pero ¿cuál sería la más eficiente?

¡Saludos amigos!

Syntax: [ Download ] [ Hide ]
Using perl Syntax Highlighting
my @a = ();
$tot = 1;

$a[0] = rand($tot);
$tot -= $a[0];

for ($i = 1; $i <= 23; $i++) {
        $a[$i] = rand($tot);
        $tot -= $a[$i]
}

$a[24] = $tot;

$i = 0;
foreach $val (@a) {
        $i++;
        $sum += $val;
        print "$i $a[$i] $sum\n";
}


Nota Jue Jun 25, 2009 7:32 pm
Avatar de Usuario
Administrador
Registrado: Dom Jul 24, 2005 6:12 pm
Ubicación: Valladolid, España
Mensajes: 9518
Buenas...

La solución propuesta está bien... salvo por el detalle que el casillero 24, en algunas ocasiones, se llevará buena parte del resto no colocado en las posiciones anteriores.

Yo he escogido la solución del juego del pachinko, basado en el quincunce o Tablero de Galton: un tablero lleno de clavos y unas bolitas que van cayendo, para acabar en unos casilleros.

En esto caso tenemos 1000 bolitas que las iremos haciendo caer de forma aleatoria por los 25 casilleros. Luego, es cuestión de dividir el número de bolitas por 1000:

Syntax: [ Download ] [ Hide ]
Using perl Syntax Highlighting
#!/usr/bin/perl
use strict;
use warnings;
use diagnostics;

my $ancho = shift() || 25;  # El usuario nos pasa el tamaño o tomamos 25 por defecto

my @array;

for (0 .. 999) {            # Tenemos 1000 bolitas,
    $array[                 # que caen en un casillero,
        rand $ancho         # elegido al azar,
    ]++;                    # aumentando el número de bolitas en el casillero.
}

my $total = 0;

print "Dato\tNúmero\n";

for my $i (0 .. $#array) {
    my $v = $array[$i] / 1000;
    printf "%d\t%4.3f\t%s\n", $i, $v, '*' x $array[$i];
    $total += $v;
}

printf "\nSUMA:\t%4.3f\n", $total;


Una salida cualquiera:
Código:
Dato    Número
0       0.038   **************************************
1       0.045   *********************************************
2       0.042   ******************************************
3       0.047   ***********************************************
4       0.050   **************************************************
5       0.038   **************************************
6       0.043   *******************************************
7       0.044   ********************************************
8       0.022   **********************
9       0.038   **************************************
10      0.034   **********************************
11      0.034   **********************************
12      0.039   ***************************************
13      0.048   ************************************************
14      0.041   *****************************************
15      0.035   ***********************************
16      0.046   **********************************************
17      0.043   *******************************************
18      0.026   **************************
19      0.042   ******************************************
20      0.046   **********************************************
21      0.034   **********************************
22      0.042   ******************************************
23      0.037   *************************************
24      0.046   **********************************************

SUMA:   1.000


Puede parecer extraño que usemos matemática de enteros para luego ofrecer el resultado como si fuera un flotante, pero... se utiliza mucho más de lo que creemos.

¿Alguien da otra solución?

_________________
JF^D Perl programming


Nota Sab Jun 27, 2009 7:30 pm
Avatar de Usuario
Perlero Frecuente
Registrado: Jue Ene 03, 2008 3:19 pm
Mensajes: 175
explorer, el método que propones tiene un problema, y es que los números que genera, en realidad, no son demasiado aleatorios. Además, en contra de lo que podría parecer, cuantas mas bolitas simulas, menos aleatorios son los números.

Para probarlo he hecho unas pequeñas modificaciones a tu script para que acepte un número variable de bolitas y para que al final imprima también la desviación típica de los números generados:

Syntax: [ Download ] [ Hide ]
Using perl Syntax Highlighting
#!/usr/bin/perl
use strict;
use warnings;
use diagnostics;

my $bolitas = shift() || 1000;
my $ancho = shift() || 25;  # El usuario nos pasa el tamaño o tomamos 25 por defecto

my @array = (0) x $ancho;

for (1 .. $bolitas) {       # Tenemos algunas bolitas,
    $array[                 # que caen en un casillero,
        rand $ancho         # elegido al azar,
    ]++;                    # aumentando el número de bolitas en el casillero.
}

my $total = 0;
my $total2 = 0;
# print "Dato\tNúmero\n";

for my $i (0 .. $#array) {
    my $v = $array[$i] / $bolitas;
    # printf "%d\t%6.5f\n", $i, $v;
    $total  += $v;
    $total2 += $v * $v;
}

printf " SUMA:\t%6.5f\n", $total;
printf "s:\t%6.5f\n", sqrt($total2 / $bolitas - ($total / $bolitas) ** 2);
 


Que al ejecutarlo para 10, 100, 1000, 10000 y 100000 da estos valores:

Código:
$ perl bolitas.pl 10
SUMA:   1.00000
s:   0.04472
$ perl bolitas.pl 100
SUMA:   1.00000

$ perl bolitas.pl 1000
SUMA:   1.00000
s:   0.00631
$ perl bolitas.pl 10000
SUMA:   1.00000
s:   0.00200
$ perl bolitas.pl 100000
SUMA:   1.00000
s:   0.00063


Estadísticamente, los números siguen una distribución binomial, de $media = 1 / $ancho y varianza = 1/$ancho * (1 - 1/$ancho) / $bolitas, que tiende a cero cuando $bolitas crece.

La solución al problema no es fácil. Lo primero que hace falta es saber para qué se van a usar los números para a continuación buscar una distribución que se ajuste a ese uso y finalmente desarrollar un método que genere números según la misma.


Nota Sab Jul 04, 2009 10:41 am
Avatar de Usuario
Administrador
Registrado: Dom Jul 24, 2005 6:12 pm
Ubicación: Valladolid, España
Mensajes: 9518
Re: Números aleatorios que siempre suman 1
Bueno, otra opción... el "loco repartidor de tarta ciego".

Tenemos una tarta dividida en 1000 partes. Se acercan los comensales y comienza a repartir trozos de tamaño aleatorio y los reparte de forma aleatoria.

Syntax: [ Download ] [ Hide ]
Using perl Syntax Highlighting
#!/usr/bin/perl
use strict;
use warnings;
use diagnostics;

my $comensales = shift() || 25;    # El usuario nos pasa el número o tomamos 25 por defecto

my $tarta      = shift() || 1000;

my @array;

while ($tarta > 0) {

    my $trozo = rand $tarta;

    $array[rand $comensales] += $trozo;

    $tarta -= $trozo;
}

my $total = 0;

print "Dato\tNúmero\n";

for my $i (0 .. $#array) {
    $array[$i] = 0 if !defined $array[$i];

    my $v = $array[$i] / 1000;
    printf "%d\t%4.3f\t%s\n", $i, $v, '*' x $array[$i];
    $total += $v;
}

printf "\nSUMA:\t%4.3f\n", $total;

Un ejemplo de salida:
Código:
Dato    Número
0       0.006   ******
1       0.000
2       0.000
3       0.000
4       0.000
5       0.080   *******************************************************************************
6       0.796   *******************************************************************************
***********************************************************************************************
***********************************************************************************************
***********************************************************************************************
***********************************************************************************************
***********************************************************************************************
***********************************************************************************************
***********************************************************************************************
****************************************************
7       0.000
8       0.000
9       0.000
10      0.000
11      0.014   *************
12      0.000
13      0.000
14      0.000
15      0.023   ***********************
16      0.000
17      0.000
18      0.000
19      0.033   *********************************
20      0.000
21      0.000
22      0.041   *****************************************
23      0.005   *****
24      0.000

SUMA:   1.000

_________________
JF^D Perl programming


Responder al tema  [ 5 mensajes ] 

Reglas del Foro
No puedes abrir nuevos temas en este Foro
No puedes responder a temas en este Foro
No puedes editar tus mensajes en este Foro
No puedes borrar tus mensajes en este Foro
No puedes enviar adjuntos en este Foro

Publicidad

Socializa

Síguenos por Twitter

Suscríbete GRATUITAMENTE al Boletín de Perl en Español

Saltar a:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
Traducción al español por Huan Manwë para phpbb-es.com
phpBB SEO