Je fais un générateur de nombres aléatoires. Il demande combien de chiffres l’utilisateur veut faire figurer dans le numéro. Par exemple, si vous entrez 2, il générera des nombres aléatoires entre 10 et 99. J’ai créé le générateur mais mon problème est que les nombres ne sont pas uniques.
Voici mon code. Je ne sais pas pourquoi il ne génère pas de numéro unique. Je pensais que srand (time (null)) le ferait.
void TargetGen::randomNumberGen() { srand (time(NULL)); if (intLength == 1) { for (int i = 0; i max) { intQuantity = max; } cout << number1 % max + min << "\t"; } } else if (intLength == 2) { for (int i = 0; i max) { intQuantity = max; } cout << number1 % max + min << "\t"; } } if (intLength == 3) { for (int i = 0; i max) { intQuantity = max; } cout << number1 % max + min << "\t"; } } else if (intLength == 4) { for (int i = 0; i max) { intQuantity = max; } cout << number1 % max + min << "\t"; } } if (intLength == 5) { for (int i = 0; i max) { intQuantity = max; } cout << number1 % max + min << "\t"; } } else if (intLength == 6) { for (int i = 0; i max) { intQuantity = max; } cout << number1 % max + min << "\t"; } } if (intLength == 7) { for (int i = 0; i max) { intQuantity = max; } cout << number1 % max + min << "\t"; } } else if (intLength == 8) { for (int i = 0; i max) { intQuantity = max; } cout << number1 % max + min << "\t"; } } if (intLength == 9) { for (int i = 0; i max) { intQuantity = max; } cout << number1 % max + min << "\t"; } } }
Ok, alors je pensais avoir trouvé un moyen de faire cela sans tableaux, mais cela ne fonctionnait pas avant de passer à la méthode de pêche. Quelqu’un peut-il me dire pourquoi cela ne fonctionne pas? Il est supposé prendre essentiellement le nombre aléatoire mis cela dans variable numGen. Puis dans la variable b = numgen. Il suffit de tenir ce que numGen était. Lorsque la boucle passe et génère un autre nombre aléatoire, elle le compare à l’ancien numéro et, s’il n’est pas égal, elle le restitue. S’il est égal à l’ancien numéro plutôt que de le sortir, il sera incriminé de sorte qu’il parcourt la boucle sans ignorer entièrement le nombre. Cependant, lorsque je fais cela, c’est infiniment de boucles. Et je ne sais pas pourquoi.
if (intLength == 1) {
for (int i = 0; i max) { intQuantity = max; } for (int k = 0; k < 1; k++) { cout << numGen << "\t"; int b = numGen; } int b = numGen; if (b != numGen ) { cout << numGen << "\t"; } else { i--; } } }
Tout le monde a des attentes intéressantes en ce qui concerne les nombres aléatoires – apparemment, vous vous attendez à ce que les nombres aléatoires soient uniques ! Si vous utilisez un bon générateur de nombres aléatoires, vos nombres aléatoires ne seront jamais garantis comme étant uniques.
Pour que cela soit plus évident, si vous vouliez générer des nombres aléatoires compris dans la plage [1, 2] et que vous deviez générer deux nombres, vous obtiendriez (normalement, attendez-vous à) l’une des quatre possibilités suivantes avec une probabilité égale:
1, 2
2, 1
1, 1
2, 2
Cela n’a aucun sens de demander à un bon générateur de nombres aléatoires de générer les deux premiers, mais pas les deux derniers.
Maintenant, prenez une seconde pour penser à quoi vous attendre si vous avez demandé de générer trois nombres dans la même plage … 1, 2, alors quoi ??
L’unicité, par conséquent, n’est pas et ne sera pas une propriété d’un générateur de nombres aléatoires.
Votre problème spécifique peut toutefois nécessiter un caractère unique. Dans ce cas, vous devez effectuer des travaux supplémentaires pour garantir l’unicité.
Une solution consiste à garder un onglet sur lequel les numéros sont déjà choisis. Vous pouvez les conserver dans un set et les repasser si vous en avez un que vous avez obtenu plus tôt. Toutefois, cela n’est efficace que si vous choisissez un petit ensemble de nombres par rapport à votre plage; si vous choisissez la plus grande partie de la plage, la fin du processus devient inefficace.
Si le nombre que vous allez sélectionner correspond à la plus grande partie de la plage, il est préférable d’utiliser un tableau de la plage et d’utiliser un algorithme de réorganisation méticuleux pour mélanger les chiffres. (Le mélange Fisher-Yates devrait faire l’affaire.)
Indice 0: Utilisez le résidu quadratique de la théorie des nombres; un entier q est appelé résidu quadratique modulo p s’il est congruent à un carré parfait modulo p ; c’est-à-dire, s’il existe un entier x tel que:
x 2 ≡ q (mod p)
Astuce 1: Théorème: En supposant que p est un nombre premier, le résidu quadratique de x est unique tant que 2x
0 2 ≡ 0 (mod 13)
1 2 ≡ 1 (mod 13)
2 2 ≡ 4 (mod 13)
3 2 ≡ 9 (mod 13)
4 2 ≡ 3 (mod 13)
5 2 ≡ 12 (mod 13)
6 2 ≡ 10 (mod 13)
Astuce 2: Théorème: En supposant que p est un nombre premier tel que p ≡ 3 (mod 4), non seulement x 2 % p (le résidu quadratique) est unique pour 2x
2 % p est également unique pour 2x> p. Par exemple:
0 2 % 11 = 0
1 2 % 11 = 1
2 2 % 11 = 4
3 2 % 11 = 9
4 2 % 11 = 5
5 2 % 11 = 3
11 – 6 2 % 11 = 8
11 – 7 2 % 11 = 6
11 – 8 2 % 11 = 2
11 – 9 2 % 11 = 7
11 – 10 2 % 11 = 10
Ainsi, cette méthode nous fournit une permutation parfaite de 1 à 1 sur les entiers inférieurs à p, p pouvant être tout nombre premier tel que p ≡ 3 (mod 4).
Astuce 3:
unsigned int UniqueRandomMapping(unsigned int x) { const unsigned int p = 11; //any prime number satisfying p ≡ 3 (mod 4) unsigned int r = ((unsigned long long) x * x) % p; if (x <= p / 2) return r; else return p - r; }
Je ne me suis pas inquiété des mauvais nombres d'entrée (par exemple, hors de scope).
Remarques
Je suppose que vous pouvez trouver un moyen de déterminer le nombre de nombres que vous souhaitez utiliser. C’est assez simple, car une entrée utilisateur de 2 va de 10 à 99, 3 de 100 à 999, etc.
Si vous voulez créer votre propre implémentation de nombres uniques générés de manière aléatoire, consultez ces liens.
http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
Voici une implémentation très similaire: https://stackoverflow.com/a/196065/2142219
En substance, vous créez un tableau d’entiers X, tous définis sur la valeur de leur index. Vous sélectionnez de manière aléatoire un index entre 0 et MAX, en prenant la valeur de cet index et en l’échangeant avec la valeur max. MAX est alors décrémenté de 1 et vous pouvez le répéter en sélectionnant de manière aléatoire un index compris entre 0 et MAX – 1.
Cela vous donne un tableau aléatoire de 0 à 999 nombres entiers sans doublons.
Voici deux approches possibles pour générer des nombres aléatoires uniques dans une plage.
std::set
, et jetez et régénérez les nombres tant qu’ils sont déjà dans l’ensemble. Cette approche n’est pas recommandée si vous souhaitez générer un grand nombre de nombres aléatoires, en raison du paradoxe de l’anniversaire. Les générateurs aléatoires standard ne généreraient jamais de nombres uniques, dans ce cas ils ne seraient pas indépendants.
Pour générer des numéros uniques, vous devez:
ou
Tout d’abord, srand()
/ rand()
ont généralement une période de 2 ^ 32, ce qui signifie qu’après avoir appelé srand()
, rand()
itérera en interne sur des entiers distincts lors des 2 ^ 32 premiers appels à rand()
. Néanmoins, rand()
peut très bien renvoyer un résultat de moins de 32 bits: par exemple, un int
compris entre 0
et RAND_MAX
où RAND_MAX
est 2 ^ 31-1 ou 2 ^ 15-1, de sorte que vous pouvez voir des résultats répétés en tant qu’appelant de rand()
Vous avez probablement lu sur la période cependant, ou le commentaire de quelqu’un l’a fait avec conscience, et d’une manière ou d’une autre, cela a été confondu avec l’unicité …
Deuxièmement, tout appel à rand()
génère un nombre beaucoup plus grand que vous le souhaitez, et vous le faites …
number1 % max
Le résultat de ” number1 % max
” se situe dans la plage 0 <= N <= max
, mais le nombre aléatoire lui-même peut avoir été un multiple de max
supérieur à celui-ci. En d'autres termes, deux nombres aléatoires distincts qui diffèrent par un multiple de max
produisent toujours le même résultat pour number1 % max
dans votre programme.
Pour obtenir des nombres aléatoires distincts dans une plage, vous pouvez préremplir un std::vector
avec tous les nombres, puis std::shuffle
.