2008-10-03 7 views
13

Je cherche un générateur de nombres pseudo-aléatoires qui serait spécialisée pour travailler rapidement quand il est donné une graine avant de générer chaque numéro. La plupart des générateurs que j'ai vus jusqu'à présent supposent que vous avez mis une graine une fois et ensuite générer une longue séquence de nombres. La seule chose qui ressemble un peu à ce que j'ai vu jusqu'ici est Perlin Noise, mais elle génère des données trop "lisses" - pour des entrées similaires, elle tend à produire des résultats similaires.générateur pseudo-aléatoire rapide pour le contenu de la procédure

La déclaration du générateur devrait ressembler à:

int RandomNumber1(int seed); 

Ou:

int RandomNumber3(int seedX, int seedY, int seedZ); 

Je pense avoir une bonne RandomNumber1 devrait être suffisante, car il est possible de mettre en œuvre RandomNumber3 en hachant ses entrées et en passant le résultat dans le RandomNumber1, mais j'ai écrit le deuxième prototype au cas où une implémentation pourrait utiliser les entrées indépendantes. L'utilisation prévue pour ce générateur est de l'utiliser pour le générateur de contenu procédural, comme la génération d'une forêt en plaçant des arbres dans une grille et en déterminant une espèce d'arbre aléatoire et des décalages spatiaux aléatoires pour chaque emplacement.

Le générateur doit être très efficace (moins de 500 cycles CPU), parce que le contenu de la procédure est créée en quantités énormes en temps réel pendant le rendu.

+0

La raison pour laquelle le bruit Perlin est semblable à ce que vous demandez est que le bruit Perlin utilise une fonction pseudo-aléatoire déterministe (reproductible) pour faire partie de son travail (et aplanit le résultat). Si vous regardez une implémentation de bruit Perlin, en particulier les plus anciennes, vous trouverez souvent le type de fonction "aléatoire" efficace et reproductible que vous recherchez, bien que le langage, le domaine et la portée varient. Par exemple. 'RandomNumber (graine vec2, float x, flottant y) {return fract (sin (point (graine + vec2 (fx, fy), vec2 (12.9898,78.233))) * 43758.5453); } '(GLSL ES) – LarsH

+0

J'ai aussi essayé de faire une recherche sur cette question, et je suis arrivé à la conclusion que le mot« générateur »implique le comportement séquentiel en continu que nous essayons d'éviter. C'est pourquoi un PRN ** G ** est généralement compris comme fournissant des «fonctions» dynamiques, pas strictement déterministes. Peut-être que nous aurions un meilleur succès dans la recherche si nous recherchions PRNF (fonction) plutôt que PRNG. https://blogs.unity3d.com/2015/01/07/a-primer-on-repeatable-random-numbers/ les appelle "fonctions de hachage aléatoires". – LarsH

Répondre

19

On dirait que vous demandez une fonction de hachage plutôt qu'une PRNG. Googling «fonction de hachage rapide» donne plusieurs résultats prometteurs.

For example:

uint32_t hash(uint32_t a) 
    a = (a^61)^(a >> 16); 
    a = a + (a << 3); 
    a = a^(a >> 4); 
    a = a * 0x27d4eb2d; 
    a = a^(a >> 15); 
    return a; 
} 

Edit: Eh oui, certaines fonctions de hachage regard nettement plus approprié que d'autres.

Pour vos besoins, il devrait être suffisant pour le globe oculaire theFunction et vérifier qu'un seul changement bit dans l'entrée se propage à un bon nombre de bits de sortie.

+0

J'espère que c'est une bonne direction à suivre. Au premier coup d'oeil il me semble que les fonctions de hachage ont une propriété importante (distribution uniforme), je ne suis pas sûr que sa sortie puisse être considérée comme "aléatoire" - comment savoir pour une fonction particulière combien sa sortie ressemble au bruit ? – Suma

+3

Un test pour une bonne fonction de hachage est de lui donner la suite d'entiers 0, 1, 2 .. et de tester la sortie pour 'aléatoire' en utilisant des tests de générateur de nombres pseudo-aléatoires. – Aaron

+1

Bonne réponse, même si je ne suis pas d'accord avec "fonction de hachage * plutôt que * un PRNG." En général, les fonctions de hachage ne sont pas toujours de bons générateurs de nombres aléatoires (ils sont conçus plus pour d'autres propriétés: https://en.wikipedia.org/wiki/Hash_function#Properties), et les OP * ont * besoin d'une certaine qualité de aléatoire, ou ses forêts auront l'air faux.Cela étant dit, certaines fonctions de hachage font des PRNG «aléatoires», et elles sont certainement déterministes comme le demande le PO. – LarsH

9

Eh oui, vous êtes à la recherche d'un algorithme de hachage entier rapide plutôt qu'un PRNG.

Ce page a quelques algorithmes, je suis sûr que vous trouverez beaucoup plus maintenant que vous connaissez les termes de recherche appropriés.

Modifier: La page d'origine a été supprimée, une version en direct peut être found on GitHub.

2

voir std::tr1::ranlux3, ou d'autres générateurs de nombres aléatoires qui font partie d'additions TR1 à la bibliothèque standard C++. J'ai suggéré mt19937 initialement, mais ensuite vu votre note qu'il doit être très rapide. TR1 devrait être disponible sur Microsoft VC++ et GCC, et peut également être trouvé dans les bibliothèques de boost qui supportent encore plus de compilateurs.

exemple adapté de boost documentation:

#include <random> 
#include <iostream> 
#include <iterator> 
#include <functional> 
#include <algorithm> 
#include <ctime> 
using namespace std; 
using namespace std::tr1; 
int main(){ 
    random_device trueRand; 
    ranlux3 rng(trueRand); // produces randomness out of thin air 
          // see pseudo-random number generators 
    uniform_int<> six(1,6); // distribution that maps to 1..6 
          // see random number distributions 
    variate_generator<ranlux3&, uniform_int<> > 
      die(rng, six); // glues randomness with mapping 

    // simulate rolling a die 
    generate_n(ostream_iterator<int>(cout, " "), 10, ref(die)); 
} 

exemple sortie:

2 4 4 2 4 5 4 3 6 2 

Tout générateur de nombres aléatoires TR1 peut ensemencer une quelconque autre générateur de nombres aléatoires. Si vous avez besoin de résultats de meilleure qualité, pensez à alimenter la sortie de mt19937 (qui est plus lente mais de meilleure qualité) dans un minstd_rand ou un randlux3, qui sont des générateurs plus rapides.

0

Si la mémoire n'est pas vraiment un problème et que la vitesse est de la plus haute importance, vous pouvez pré-construire un grand nombre de nombres aléatoires et simplement l'itérer au moment de l'exécution. Par exemple, avoir un programme séparé générer 100.000 nombres aléatoires et l'enregistrer comme son propre fichier comme

unsigned int randarray [] = {1,2,3, ....}

comprennent alors ce fichier dans votre compiler et au moment de l'exécution votre fonction de nombre aléatoire a seulement besoin de tirer des nombres de ce tableau et revenir au début quand il atteint la fin.

+0

Le calcul d'un hachage simple comme dans http://stackoverflow.com/questions/167735/#167764 sera presque toujours plus rapide que l'accès à un immense tableau (un énorme tableau ne rentrera pas dans le cache, donc l'accès est lent) – Suma

+0

profilé sur mon PC et en utilisant ma méthode de table de recherche par rapport à la fonction de hachage, la table de recherche est 13 fois plus rapide. – KPexEA

+0

La table de recherche peut être plus rapide lorsqu'elle est assez petite pour tenir dans le cache L2, et lorsque vous n'utilisez pas le cache L2 pour autre chose - ce qui était probablement le cas dans votre test. Si vous voulez tester les performances du monde réel, vous devez effectuer un traitement de données important entre les recherches. – Suma

5

Voici un petit générateur de nombres aléatoires développé par George Marsaglia. Il est un expert dans le domaine, donc vous pouvez être sûr que le générateur a de bonnes propriétés statistiques.

v = 36969*(v & 65535) + (v >> 16); 
u = 18000*(u & 65535) + (u >> 16); 
return (v << 16) + u; 

Ici, u et v sont des entiers non signés. Initialisez-les à des valeurs non nulles. Chaque fois que vous générez un nombre aléatoire, stockez u et v quelque part. Vous pouvez envelopper dans une fonction pour correspondre à votre signature ci-dessus (sauf les ints ne sont pas signés.)

+0

Malheureusement, cela ne correspond pas à la question. J'ai besoin de fournir mes propres U et V à chaque fois, de ne pas les stocker quelque part et de les mettre à jour entre les itérations. La fonction doit toujours produire la même sortie avec les mêmes entrées. – Suma

+0

@Suma: Pourquoi ne pouvez-vous pas fournir vos propres U et V à chaque fois si vous les transmettez simplement comme paramètres à cette fonction? Et avoir le même U et le même V à chaque fois produira toujours le même résultat. Cela correspond exactement à votre question! – Mecki

+0

J'ai essayé ceci et n'ai pas obtenu de bons résultats. La variation de 1 par 1 ne fait pas varier la sortie de manière significative. – Aranda

0

J'utilise le code suivant dans ma bibliothèque de nombres aléatoires Java - cela a fonctionné plutôt bien pour moi. J'utilise aussi ceci pour générer du contenu procédural.

/** 
* State for random number generation 
*/ 
private static volatile long state=xorShift64(System.nanoTime()|0xCAFEBABE); 

/** 
* Gets a long random value 
* @return Random long value based on static state 
*/ 
public static long nextLong() { 
    long a=state; 
    state = xorShift64(a); 
    return a; 
} 

/** 
* XORShift algorithm - credit to George Marsaglia! 
* @param a initial state 
* @return new state 
*/ 
public static final long xorShift64(long a) { 
    a ^= (a << 21); 
    a ^= (a >>> 35); 
    a ^= (a << 4); 
    return a; 
} 
Questions connexes