web-dev-qa-db-fra.com

Besoin d'un générateur aléatoire rapide pour c ++

J'essaie de faire un échange opt-3 sur mon générateur TSP pour les distances euclidiennes, et comme j'ai souvent plus de ~ 500 nœuds, j'ai besoin de sélectionner au hasard au moins 1 des 3 nœuds que je veux essayer d'échanger .

Donc, fondamentalement, j'ai besoin d'une fonction de nombre aléatoire qui est rapide. (le Rand () normal est beaucoup trop lent) Il n'a pas besoin d'être génial, juste bon assez .

EDIT: J'ai oublié de mentionner, je suis assis dans un environnement où je ne peux pas ajouter de bibliothèques à l'exception de la bibliothèque de langues standard (comme STL, iostream, etc.). Donc pas de boost = /

44
Martin Andersson

L'autre thread a mentionné le générateur xorshf de Marsaglia, mais personne n'a publié le code.

static unsigned long x=123456789, y=362436069, z=521288629;

unsigned long xorshf96(void) {          //period 2^96-1
unsigned long t;
    x ^= x << 16;
    x ^= x >> 5;
    x ^= x << 1;

   t = x;
   x = y;
   y = z;
   z = t ^ x ^ y;

  return z;
}

J'ai utilisé celui-ci partout. Le seul endroit où cela a échoué était lorsque j'essayais de produire des matrices binaires aléatoires. Passé environ les matrices 95x95, il commence à générer trop peu ou trop de matrices singulières (j'oublie lesquelles). Il a été démontré que ce générateur est équivalent à un registre de rétroaction à décalage linéaire. Mais à moins que vous ne fassiez de la cryptographie ou que vous ne travailliez sérieusement à Monte Carlo, ce générateur bascule.

62
AndyV

Deux bonnes alternatives sur le site d'Intel:

1) fastrand - il est 2,01 X plus rapide que le std Rand (). La routine renvoie un entier, une plage de valeurs de sortie similaire à C lib.

inline int fastrand() { 
  g_seed = (214013*g_seed+2531011); 
  return (g_seed>>16)&0x7FFF; 
} 

2) une version SSE (voir le lien ci-dessous) est environ 5,5 fois plus rapide que std Rand () mais elle génère 4 valeurs aléatoires à la fois, nécessite un processeur avec sse (presque toutes le font) et est plus compliqué.

http://software.intel.com/en-us/articles/fast-random-number-generator-on-the-intel-pentiumr-4-processor/

28
Sunsetquest

Voir ces générateurs de George Marsaglia, expert en générateur de nombres aléatoires. Ils sont implémentés en tant que macros C, et ils sont rapides comme l'éclair, juste quelques opérations par nombre généré.

12
John D. Cook

Mersenne Twister a quelques implémentations rapides.

6
lhf

À partir de Ivy Bridge architecture Intel a ajouté RdRand instruction CPU et AMD l'a ajouté plus tard en juin 2015. Donc, si vous ciblez un processeur suffisamment nouveau et que cela ne vous dérange pas d'utiliser (inline) Assembly, le moyen le plus rapide pour générer des nombres aléatoires devrait être d'appeler RdRand l'instruction CPU pour obtenir un nombre aléatoire de 16 ou 32 ou 64 bits comme décrit ici . Faites défiler vers le milieu de la page pour voir des exemples de code. Sur ce lien, il y a aussi un exemple de code pour vérifier le processeur actuel pour la prise en charge de l'instruction RdRand, et voir également Wikipedia pour une explication sur la façon de le faire avec l'instruction CPUID.

Question connexe: tiliser le véritable générateur de nombres aléatoires de Sandy Bridge? (bien que selon Wikipedia, les instructions RdRand soient apparues pour la première fois dans Ivy Bridge, mais pas dans l'architecture Sandy Bridge comme le dit cette question)

Exemple de code C++ basé sur _ rdrand64_step () :

#include <immintrin.h>

uint64_t randVal;
if(!_rdrand64_step(&randVal)) {
  // Report an error here: random number generation has failed!
}
// If no error occured, randVal contains a random 64-bit number
6
Serge Rogatch

Même si ce message a des années, il est apparu lorsque je cherchais une réponse similaire, et la réponse que j'ai utilisée, n'y figure même pas. J'ajoute donc celui que j'ai trouvé;

#include <random> Entrée msdn

Cette approche va construire un générateur aléatoire autonome, et je l'ai trouvé beaucoup plus aléatoire que Rand()%x; sur quelques centaines de milliers d'itérations. Rand()% ne lancerait jamais plus de 16 têtes/queues d'affilée, alors qu'il devrait le faire à chaque 65 000 tentatives. Celui-ci fait non seulement cela, mais il le fait dans un quart du temps.

Voici comment j'implémente #include <random> Moi-même:

//create rng_gen, using mt technique, with range 0,1 (coin) and 1,6(dice);
std::random_device rd; //seed
std::mt19937 gen(rd()); //seed for rd(Mersenne twister)
std::uniform_int_distribution<> rng_coin(0, 1); //rng1 range
std::uniform_int_distribution<> rng_dice(1, 6); ///rng2 range

rng_coin(gen); //will apply rng1 range on (gen) object. Is very fast
rng_dice(gen); //will apply rng2 range, returns int.

//will output 1000 cointosses to console
for (int i=0;i<1000;++i)std::cout<<rng_coin(gen)<<"\n";
//will generate 1000 dice throws
for (int i=0;i<1000;++i)rng_dice(gen);
2
Charlie

La bibliothèque Boost possède un ensemble de générateurs aléatoires. Le graphique des performances peut être trouvé ici .

EDIT: Cette réponse était ici avant la modification de la question d'origine. Mais j'espère que cela pourrait être utile, alors je le laisse ici.

1

Rand () est vraiment rapide, et je ne pense pas que vous trouverez beaucoup plus rapidement.

Si cela vous ralentit (ce dont je doute un peu), vous avez besoin d'un changement d'architecture.

Je recommande de préremplir une longue liste avec des nombres aléatoires, puis lorsque vous en avez besoin, prenez-en simplement un dans la liste, plutôt que d'en générer un. Vous pourrez peut-être remplir à nouveau la liste avec un fil d'arrière-plan.

1
abelenky

pouvez-vous pré-générer un tas de bits aléatoires à l'avance et les décoller 2 à la fois (puisque vous n'avez besoin que d'un nombre aléatoire entre 1 et 3)?

0
Mikeb

Je pense que WELL est assez bon, et WELL512a est assez court. http://www.iro.umontreal.ca/~panneton/WELLRNG.html WELL44497a est complexe à l'époque aussi. Cependant, WELL génère un nombre compris entre 0 et 1.

0
user2700021