0
votes

rand () donne presque le même nombre à chaque fois

J'apprends C et je souhaite générer un nombre entre 0 et 6400. Voici le code que j'ai trouvé:

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6282

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6282

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6285

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6285

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6289

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6289

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6292

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6292

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6295

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6298

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6298

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6302

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6302

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6305

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6305

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6308

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6308

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6311

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6311

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6315

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6315

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6318

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6318

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6321

K:\C\Labo\Oefeningen 2019>

Lorsque je compile et exécute ce code à partir de la ligne de commande, j'obtiens des résultats très étranges:

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

int main()
{
    srand(time(0));
    int i = (rand() % 6401);
    printf("Random number between 0 and 6400: %d\n", i);
    return 0;
}

Les nombres sont tous différents mais je m'attendrais à une distribution quelque peu égale entre 0 et 6400. Ce qui est étrange, c'est que j'utilisais la même fonction sans problème il y a une heure? (Je l'utilisais auparavant pour générer des nombres plus petits.) Je suis certain que c'est quelque chose de vraiment stupide qui me manque mais je suis bloqué depuis une heure maintenant.

EDIT: Je sais que cela donnera la même valeur lorsque vous exécuterez le code dans la même seconde. J'ai attendu plusieurs secondes (10-20) entre les exécutions et j'obtiens toujours le même résultat? Les valeurs sont rarement les mêmes, elles sont juste très très très similaires à 100% du temps. Comment contourner ce problème?


2 commentaires

time (0) renvoie le nombre de secondes écoulées depuis 1970. Sa valeur doit changer toutes les secondes. Donc, si vous exécutez ce programme plus d'une fois en une seconde, vous pouvez obtenir les mêmes résultats. Mais une fois le temps passé, les valeurs ne devraient plus être les mêmes. Vous pouvez ajouter la sortie de cette fonction à la console à des fins de comparaison. Si vous avez besoin d'une fraction de seconde, vous pouvez utiliser gettime , qui nécessite un pointeur struct comme paramètre.


Double possible de srand (time (0)) et génération de nombres aléatoires , Comprendre le comportement de srand (time (0)) , srand (time (0)) vous ne faites pas de nombres aléatoires? , etc.


5 Réponses :


0
votes

Les ordinateurs ne génèrent pas vraiment de nombres aléatoires. Ainsi, lorsque vous exécutez votre code deux fois sur la même seconde, il renvoie la même valeur. Afin d'avoir un meilleur résultat, vous pouvez ajouter la valeur de getpid () dans srand.

Gardez à l'esprit que ce n'est toujours pas vraiment aléatoire.


1 commentaires

Oui, mais il renvoie également une valeur presque identique lorsque j'attends plus de 30 secondes.



3
votes

time () a une résolution de 1 seconde. Ainsi, votre programme ne générera à une valeur différente qu'après une demi-seconde en moyenne.

Si votre compilateur prend en charge C11, vous pouvez utiliser une fonction de résolution plus élevée, timespec_get () . Votre srand (time (0)); se transformera alors en ce qui suit:

srand(time(0)+clock());

Ici ts.tv_nsec est la partie nanoseconde de l'horodatage, dont la résolution devrait être suffisamment bonne pour votre objectif.

Si votre compilateur ne prend pas en charge C11, vous pouvez toujours avoir une meilleure source de graine aléatoire que time ( ) , avec une résolution d'environ une milliseconde (la résolution réelle est donnée par la macro CLOCKS_PER_SEC ): la fonction clock () . Ensuite, votre code d'amorçage sera

srand(clock());

Notez cependant qu'il peut en fait être une mauvaise source d'entropie, surtout si votre système d'exploitation n'est pas occupé, de sorte que le programme fonctionnerait quelque peu rythme prévisible. C'est parce que le début de l'ère de clock () est lié à l'exécution du programme, pas au temps réel. Il vaudrait peut-être mieux par ex. utilisez une somme de clock () et time (0) pour obtenir une valeur plus imprévisible:

struct timespec ts;
timespec_get(&ts, TIME_UTC);
srand(ts.tv_nsec);


4 commentaires

J'ai attendu plusieurs secondes entre l'exécution mais la valeur se situe toujours entre 6280 et 3000. Pour voir un changement réel, je dois attendre quelques minutes. Pourquoi donc?


@ZwarteKop Peut-être que l'implémentation de srand et rand dans votre compilateur est trop mauvaise. Essayez d'exécuter srand ((unsigned) rand () * rand ()) après le premier srand : cela pourrait donner de meilleurs résultats, même si je ne sais pas si ce sera le cas .


Belle idée avec la partie ts.tv_nsec ; ce sera essentiellement totalement aléatoire et passera par un cycle complet toutes les 1s. Vous pourriez envisager d'ajouter getpid () à cela si un cas de niche se présente.


@ JL2210 c'est POSIX, pas du pur C.



0
votes

Si votre rand est interrompu, vous pouvez essayer l'un des xorshift pseudo-aléatoire générateurs de nombres. Ils ne sont pas parfaits mais la mise en œuvre qui en résulte est très courte. Cela pourrait être suffisant pour votre propre usage.

Voici un exemple d'implémentation: j'ai utilisé cet un comme référence. / p>

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

uint64_t    xorshift64s(uint64_t seed)
{
    static uint64_t i = 1;

    if (seed != 0)
        i = seed;
    i ^= i >> 12;
    i ^= i << 25;
    i ^= i >> 27;
    i *= 0x2545f4914f6cdd1d;
    return (i >> 32);
}


int main()
{
    srand(time(0));
    int i = (rand() % 6401);
    printf("rand    : Random number between 0 and 6400: %d\n", i);
    xorshift64s(time(0));
    int j = (xorshift64s(0) % 6401);
    printf("xorshift: Random number between 0 and 6400: %d\n", j);
    return 0;
}


0 commentaires

0
votes

Si quelqu'un d'autre rencontre ce problème, je pense avoir trouvé une solution de contournement. Je sais que ce n'est pas une solution parfaite, mais c'est la seule qui a fonctionné pour moi. Je pense que le générateur de nombres aléatoires utilisé dans mon compilateur n'aime pas du tout des graines similaires. Avec cet extrait de code, il génère en fait des nombres semi-aléatoires assez acceptables:

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

int main()
{
    srand((unsigned int)time(0) * 100000000);
    int i = (rand() % 6401);
    printf("Random number between 0 and 6400: %d\n", i);
    return 0;
}

C'est là que j'ai obtenu mon compilateur de poubelle de btw: http://tdm-gcc.tdragon.net/download


0 commentaires

0
votes

Les nombres générés par rand ne sont pas vraiment aléatoires, ils sont générés avec une formule. C'est pourquoi l'ensemencement est à la fois possible et nécessaire. Selon la formule utilisée, il peut y avoir une forte corrélation entre la graine et les premiers nombres aléatoires.

Les remèdes sont d'utiliser une meilleure formule (quelque chose qui n'est pas rand ), d'utiliser une graine plus aléatoire ou de gaspiller quelques nombres aléatoires juste après l'ensemencement.


0 commentaires