web-dev-qa-db-fra.com

Comment générer des nombres aléatoires sans la fonction Rand ()?

Je veux générer des nombres (pseudo) aléatoires compris entre 0 et un nombre entier. Cela ne me dérange pas s'ils ne sont pas trop aléatoires. J'ai accès à l'heure actuelle de la journée mais pas à la fonction Rand. Quelqu'un peut-il penser à un moyen suffisamment robuste pour les générer? Peut-être, rejetant quelques bits de l'heure de la journée et prenant modulo mon entier ou quelque chose?

J'utilise c.

24
AnkurVj

Si vous recherchez un générateur pseudo-aléatoire ultra-simple, vous pouvez simplement utiliser un Registre à décalage à retour linéaire .

L'article de Wikipédia contient des extraits de code, mais le code d'un générateur 16 bits ressemblera à quelque chose comme ceci (légèrement masqué à partir de cette page ...)

  unsigned short lfsr = 0xACE1u;
  unsigned bit;

  unsigned Rand()
  {
    bit  = ((lfsr >> 0) ^ (lfsr >> 2) ^ (lfsr >> 3) ^ (lfsr >> 5) ) & 1;
    return lfsr =  (lfsr >> 1) | (bit << 15);
  }
27
Roddy

Pour les entiers "pas trop aléatoires", vous pouvez commencer par l'heure UNIX en cours, puis utiliser la formule récursive r = ((r * 7621) + 1) % 32768;. Le nième entier aléatoire entre 0 (inclus) et M (exclusif) serait r % M après la nième itération.

Ceci s'appelle un générateur congruentiel linéaire.

La formule de récurrence est ce que bzip2 utilise pour sélectionner le pivot dans son implémentation quicksort. Je ne saurais en dire d’autres fins, mais cela fonctionne plutôt bien pour celui-ci en particulier ...

10
Dennis

Réfléchissez à la mise en œuvre d’un générateur pseudo-aléatoire (qu’il ya "à l'intérieur" de Rand()), par exemple le twister de Mersenne est hautement considéré.

7
unwind

Le plus petit et simple générateur aléatoire qui fonctionne avec gammes est fourni ci-dessous avec un exemple pleinement fonctionnel.

unsigned int MyRand(unsigned int start_range,unsigned int end_range)
  {
    static unsigned int Rand = 0xACE1U; /* Any nonzero start state will work. */

    /*check for valid range.*/
    if(start_range == end_range) {
        return start_range;
    }

    /*get the random in end-range.*/
    Rand += 0x3AD;
    Rand %= end_range;

    /*get the random in start-range.*/
    while(Rand < start_range){
        Rand = Rand + end_range - start_range;
    }

    return Rand;
  }

int main(void)
{
    int i;
    for (i = 0; i < 0xFF; i++)
    {
    printf("%u\t",MyRand(10,20));
    }
    return 0;
}
0
HaSeeB MiR

Le seul moyen "robuste" (pas facilement prévisible) de le faire est d'écrire votre propre générateur de nombres pseudo-aléatoires et de le modifier avec l'heure actuelle. Lien wikipedia obligatoire: http://fr.wikipedia.org/wiki/Pseudorandom_number_generator

0
Staven

Vous pouvez obtenir le "Tiny Mersenne Twister" ici: http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/TINYMT/index.html

c est pur et simple à utiliser. Par exemple. juste en utilisant le temps:

#include "tinymt32.h"
// And if you can't link:
#include "tinymt32.c"

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

int main(int argc, const char* argv[])
{
    tinymt32_t state;
    uint32_t seed = time(0);

    tinymt32_init(&state, seed);

    for (int i=0; i<10; i++)
            printf("random number %d: %u\n", i, (unsigned int)tinymt32_generate_uint32(&state));
}
0
Dominic

Si vous ne générez pas vos chiffres trop rapidement (* 1) et que votre limite supérieure est suffisamment basse (* 2) et que votre "heure de la journée" inclut des nanosecondes, utilisez simplement ces nanosecondes.

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

int nanorand(void) {
    struct timespec p[1];
    clock_gettime(CLOCK_MONOTONIC, p);
    return p->tv_nsec % 1000;
}

int main(void) {
    int r, x;
    for (;;) {
        r = nanorand();
        do {
            printf("please type %d (< 50 quits): ", r);
            fflush(stdout);
            if (scanf("%d", &x) != 1) exit(EXIT_FAILURE);
        } while (x != r);
        if (r < 50) break;
    }
    puts("");
    return 0;
}

Et un échantillon exécuté ...

 veuillez taper 769 (<50 quits): 769 
 veuillez taper 185 (<50 quits): 185 
 veuillez taper 44 (<50 quits): 44 

(* 1) si vous les utilisez de manière interactive, un à la fois
(* 2) si vous voulez des nombres allant jusqu'à environ 1000

0
pmg