web-dev-qa-db-fra.com

Nombres aléatoires Java à l'aide d'une graine

Ceci est mon code pour générer des nombres aléatoires en utilisant une graine comme argument:

double randomGenerator(long seed) {
    Random generator = new Random(seed);
    double num = generator.nextDouble() * (0.5);

    return num;
}

Chaque fois que je donne une graine et que je tente de générer 100 nombres, ils sont tous identiques.
Comment puis-je réparer cela?

41
Rahul Bhatia

Si vous donnez la même graine, c'est normal. C'est une fonctionnalité importante permettant des tests.

Cochez cette case pour comprendre la génération pseudo-aléatoire et les graines: 

Générateur de nombres pseudo-aléatoires 

Un générateur de nombres pseudo-aléatoires (PRNG), également appelé déterministe générateur de bits aléatoires DRBG, est un algorithme permettant de générer une séquence des nombres qui se rapproche des propriétés des nombres aléatoires. Le La séquence n'est pas vraiment aléatoire en ce sens qu'elle est complètement déterminée par un ensemble relativement petit de valeurs initiales, appelé état du PRNG, qui comprend une graine vraiment aléatoire.

Si vous souhaitez avoir différentes séquences (le cas habituel lorsque vous n’accordez ni ne modifiez l’algorithme), vous devez appeler le constructeur à zéro argument qui utilise nanoTime pour essayer d’obtenir chaque fois une graine différente. Cette instance Random devrait bien sûr être conservée en dehors de votre méthode.

Votre code devrait probablement être comme ça:

private Random generator = new Random();
double randomGenerator() {
    return generator.nextDouble()*0.5;
}
68
Denys Séguret

Le moyen le plus simple est d'utiliser:

Random Rand = new Random(System.currentTimeMillis());

C'est le meilleur moyen de générer des nombres Random.

17
Pollar

Vous ne devriez pas créer de nouvelle méthode Random in. Faites-en un membre de la classe:

public class Foo {
   private Random random 

   public Foo() {
       this(System.currentTimeMillis());
   }

   public Foo(long seed) {
       this.random = new Random(seed);
   }

   public synchronized double getNext() {
        return generator.nextDouble();
   }
}

Ceci n'est qu'un exemple. Je ne pense pas que le fait d’emballer Random de cette façon ajoute de la valeur. Mettez-le dans une classe à vous qui l'utilise. 

9
duffymo

C'est le principe d'un Pseudo - RNG. Les chiffres ne sont pas vraiment aléatoires. Ils sont générés à l'aide d'un algorithme déterministe, mais la séquence des nombres générés varie en fonction de la graine. Puisque vous utilisez toujours la même graine, vous obtenez toujours la même séquence.

6
JB Nizet

Le problème est que vous ensemencez à nouveau le générateur aléatoire. Chaque fois que vous le définissez, l'état initial du générateur de nombres aléatoires est réinitialisé et le premier nombre aléatoire que vous générez sera le premier nombre aléatoire après l'état initial

2
Minion91

Si vous voulez générer plusieurs nombres en utilisant une graine, vous pouvez faire quelque chose comme ceci:

public double[] GenerateNumbers(long seed, int amount) {
    double[] randomList = new double[amount];
    for (int i=0;i<amount;i++) {
        Random generator = new Random(seed);
        randomList[i] = Math.abs((double) (generator.nextLong() % 0.001) * 10000);
        seed--;
    }
    return randomList;
}

Il affichera la même liste si vous utilisez la même graine.

2
user5479540

Plusieurs des exemples ici créent une nouvelle instance Random, mais cela n’est pas nécessaire. Il n'y a pas non plus de raison d'utiliser synchronized comme une solution. Tirez plutôt parti des méthodes de la classe ThreadLocalRandom :

double randomGenerator() {
    return ThreadLocalRandom.current().nextDouble(0.5);
}
0
Finn