88 votes

<random> génère le même numéro dans Linux, mais pas dans Windows

Le code ci-dessous est destiné à générer une liste de cinq nombres pseudo-aléatoires dans l'intervalle [1,100]. J'ai des graines de l' default_random_engine avec time(0), ce qui ramène le système de temps en temps unix. Quand j'ai compiler et exécuter ce programme sur Windows 7 à l'aide de Microsoft Visual Studio 2013, il fonctionne comme prévu (voir ci-dessous). Quand je le fais dans Arch Linux avec le compilateur g++, cependant, il se comporte étrangement.

Dans Linux, 5 numéros sera généré à chaque fois. Les 4 derniers chiffres seront différentes à chaque exécution (comme ce sera souvent le cas), mais le premier numéro reste le même.

Exemple de sortie de 5 exécutions sur Windows et Linux:

      | Windows:       | Linux:        
---------------------------------------
Run 1 | 54,01,91,73,68 | 25,38,40,42,21
Run 2 | 46,24,16,93,82 | 25,78,66,80,81
Run 3 | 86,36,33,63,05 | 25,17,93,17,40
Run 4 | 75,79,66,23,84 | 25,70,95,01,54
Run 5 | 64,36,32,44,85 | 25,09,22,38,13

Ajouter au mystère, qui est le premier nombre périodiquement incrémente de un sur Linux. Après l'obtention de la au-dessus de sorties, j'ai attendu environ 30 minutes et a de nouveau essayé de trouver que le 1er numéro a changé, et maintenant a toujours été généré comme une 26. Il a continué à augmenter par tranche de 1 périodiquement et est maintenant à 32. Il semble correspondre à l'évolution de la valeur de time(0).

Pourquoi le premier numéro rarement les modifications à travers les pistes, et quand il le fait, par incrément de 1?

Le code. Il parfaitement imprime les 5 numéros et le temps de système:

#include <iostream>
#include <random>
#include <time.h>

using namespace std;

int main()
{
    const int upper_bound = 100;
    const int lower_bound = 1;

    time_t system_time = time(0);    

    default_random_engine e(system_time);
    uniform_int_distribution<int> u(lower_bound, upper_bound);

    cout << '#' << '\t' << "system time" << endl
         << "-------------------" << endl;

    for (int counter = 1; counter <= 5; counter++)
    {
        int secret = u(e);
        cout << secret << '\t' << system_time << endl;
    }   

    system("pause");
    return 0;
}

139voto

T.C. Points 22510

Voici ce qu'il se passe:

  • default_random_engine dans libstdc++ (GCC de la bibliothèque standard) minstd_rand0, ce qui est un simple à congruence linéaire du moteur:

    typedef linear_congruential_engine<uint_fast32_t, 16807, 0, 2147483647> minstd_rand0;
    
  • La façon dont ce moteur génère des nombres aléatoires est xi+1 = (16807xi + 0) mod de 2 147 483 647.

  • Par conséquent, si les graines sont différents de 1, alors la plupart du temps le premier numéro généré diffèrent par 16807.

  • La gamme de ce générateur est [1, 2147483646]. La façon libstdc++' uniform_int_distribution cartes en un nombre entier dans l'intervalle [1, 100] est essentiellement ceci: générer un certain nombre n. Si le nombre n'est pas supérieur à 2147483600, puis revenez (n - 1) / 21474836 + 1; sinon, essayez à nouveau avec un nouveau numéro.

    Il devrait être facile de voir que, dans la grande majorité des cas, les deux ns qui ne diffèrent que par 16807 donnera le même nombre dans [1, 100] en vertu de cette procédure. En fait, on pourrait s'attendre à le nombre généré à augmenter en une sur chaque 21474836 / 16807 = 1278 secondes ou de 21,3 minutes, ce qui concorde assez bien avec vos observations.

MSVC de l' default_random_engine est mt19937, qui n'ont pas ce problème.

28voto

Casey Points 2096

L' std::default_random_engine est définie par l'implémentation. Utiliser std::mt19937 ou std::mt19937_64 à la place.

En outre, std::time et de la ctime fonctions ne sont pas très précis, utilisez les types définis dans l' <chrono> - tête à la place:

#include <iostream>
#include <random>
#include <chrono>

int main()
{
    const int upper_bound = 100;
    const int lower_bound = 1;

    auto t = std::chrono::high_resolution_clock::now().time_since_epoch().count();

    std::mt19937 e;
    e.seed(static_cast<unsigned int>(t)); //Seed engine with timed value.
    std::uniform_int_distribution<int> u(lower_bound, upper_bound);

    std::cout << '#' << '\t' << "system time" << std::endl
    << "-------------------" << std::endl;

    for (int counter = 1; counter <= 5; counter++)
    {
        int secret = u(e);

        std::cout << secret << '\t' << t << std::endl;
    }   

    system("pause");
    return 0;
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X