8
votes

Qu'est-ce qu'une distribution aléatoire en C ++ 11 en C ++ 11?

J'essaie de mettre en œuvre la classe suivante: xxx

Je veux que la classe fonctionne dans un environnement multithread. Chaque thread aura sa propre instance d'objet Moteur et il passera le moteur sur des objets de n'importe quelle classe qui a un comportement randomisé.

afin de générer numéros aléatoires uniformément la manière C ++ 11, la mise en œuvre du generateNiformRandomNumber devrait être quelque chose comme ceci: xxx

Le problème est que je Ne comprenez pas les distributions C ++ 11. Je sais que les moteurs de nombres aléatoires C ++ 11 peuvent être très gros objets (peu de kilo-octets), mais qu'en est-il des distributions? Au début, je pensais que les distributions sont simplement des foncteurs simples, où opérateur () est une fonction pure const , mais il semble que ce ne soit ni pur ni const . Selon le Référence , chaque instance de distribution a un réinitialiser () Fonction de membre. Cela signifie qu'il a un état interne potentiellement important ou peut-être une cache.

Ma question est la suivante:

  1. Les distributions ont-elles un état interne? Si oui pourquoi? La norme dis-elle quelque chose de la taille de cet état?

  2. est-ce une bonne idée de faire une mise en œuvre comme moi? Y a-t-il une meilleure façon?


3 commentaires

À titre d'exemple, j'ai mis en place un Distribution bêta dont l'état est en réalité deux distributions gamma. Réinitialiser Ne fait rien parce que ce n'est que l'exigence est que toutes les valeurs suivantes sont indépendantes des utilisations précédentes des moteurs.


@sftrabbit donc est réinitialiser () là-bas au cas où une personne fait une distribution qui accumule l'état lorsque vous appelez opérateur () ? Par exemple, chaque appel ultérieur à opérateur () pourrait vous donner une plage croissante ... qui explique également pourquoi opérateur () n'est-il pas conçu?


@Dave Oui, il n'y a aucune raison que la distribution ne peut pas changer car vous continuez à appeler opérateur () . Cela signifie simplement que les valeurs résultantes dépendent des invocations précédentes.


4 Réponses :


2
votes

Regarde vers les docs pour le Politique de modèle RandomNumberDistribution ...

réinitialiser () :

réinitialise l'état interne de l'objet de distribution. Après un appel à Cette fonction, le prochain appel à l'opérateur () sur l'objet de distribution ne sera pas dépendant des appels précédents à l'opérateur ().

Cela implique que les appels à opérateur () peuvent modifier l'état qui effets appels ultérieurs vers opérateur () . C'est à la fois pourquoi réinitialiser () existe et pourquoi opérateur () n'est pas const .

Uniform_real_distribution doit être un petit foncteur simple, comme vous l'avez dit. Il serait probablement de tenir le 2 réel s, il a été construit avec et rien d'autre. Et réinitialiser () ne devrait rien faire pour celui-là.


0 commentaires

6
votes

Une distribution peut très bien et aura généralement un certain état. La norme ne donne aucune restriction ici. Je peux penser à quelques raisons que l'état pourrait être utilisé:

  1. Une distribution de nombres aléatoires a souvent des paramètres pour le configurer. Par exemple, une distribution normale a des paramètres méchants et de variance. Ceux-ci font partie de son état parce qu'ils doivent être tenus entre des invocations.

  2. La distribution est mise en œuvre en termes d'autre distribution. Vous pouvez vraiment penser à cela comme un paramètre plus complexe. Par exemple, mon Distribution bêta Mise en œuvre maintient deux distributions gamma qui ont chacune leur propre configuration.

  3. La distribution pourrait changer avec le temps. Il n'y a rien à dire que les invocations répétées d'une distribution doivent être indépendantes. Ceci est l'endroit où la fonction réinitialiser est entrée. La plupart des distributions ont des appels indépendants vers opérateur () et donc la fonction réinitialiser ne fait rien (son la définition est vide). Toutefois, si vos appels sont dépendants, réinitialiser doit ramener la distribution à un état où le prochain appel est indépendant.

    Votre implémentation semble bien. Un uniforme_real_distribution est très peu probable d'avoir beaucoup plus d'état que les paramètres que vous le construisent.


0 commentaires

2
votes

Oui, les distributions peuvent avoir des états internes. Ils seront généralement petits, mais si vous êtes préoccupé par la taille, vérifiez-le.


0 commentaires

2
votes

la spécification pour réinitialiser () états:

Les utilisations ultérieures de D ne dépendent pas des valeurs produites par aucun moteur avant d'invoquer la réinitialisation.

qui implique que les invocations normalement de opérateur () peuvent dépendre des valeurs produites par les moteurs utilisés dans l'invocation antérieure de opérateur () . C'est-à-dire qu'une distribution peut mettre en cache ou autrement dépendre des résultats précédents du moteur.

Par exemple, une distribution Bernoulli n'a peut-être pas besoin d'un bit pour produire un résultat tandis qu'un moteur donné fournit 32 bits à la fois, la distribution peut donc mettre en cache les 32 bits et ne pas invoquer à nouveau tout moteur jusqu'à ce que 32 valeurs aient été générées.

Un autre exemple est une distribution (j'oublie qui) où l'algorithme commun produit naturellement deux valeurs à la fois. La distribution peut donc enregistrer la deuxième valeur pour l'appel suivant.

Donc oui, les distributions peuvent avoir un état interne. La norme ne place pas les exigences de la taille de cet état.

Si vous demandez s'il serait correct de partager une distribution entre les threads, ce n'est pas une bonne idée. Pour une chose, c'est une course de données et entraîne un comportement non défini, sauf si vous ajoutez une synchronisation ou de rendre la distribution constante (laquelle, même si vous pouvez le faire avec votre implémentation de la bibliothèque standard, n'est pas portable). Deuxièmement, la norme ne fait que des garanties lorsque vous utilisez les distributions et les moteurs d'une manière particulière et partageant une distribution entre plusieurs moteurs n'est pas la voie. Il est peu probable que le partage d'une distribution produira réellement de mauvaises données, mais l'OMI, c'est toujours une bonne idée de ne pas le faire. Au lieu de cela, vous pourriez avoir chaque thread conserver à la fois son propre moteur et sa propre distribution.


0 commentaires