Devrais-je appeler reset () sur ma dissortingbution aléatoire st ++ C ++ pour effacer l’état masqué?

Je voudrais envelopper les dissortingbutions de nombres aléatoires de la bibliothèque standard C ++ 11 avec des fonctions simples qui prennent comme arguments les parameters de la dissortingbution et une instance de générateur. Par exemple:

double normal(double mean, double sd, std::mt19937_64& generator) { static std::normal_dissortingbution dist; return dist(generator, std::normal_dissortingbution::param_type(mean, sd)); } 

Je souhaite éviter tout état masqué dans l’object de dissortingbution afin que chaque appel à cette fonction wrapper ne dépende que des arguments donnés. (Potentiellement, chaque appel à cette fonction pourrait prendre une instance de générateur différente.) Idéalement, je rendrais l’instance de dissortingbution static const pour assurer cela; cependant, l’ operator() la dissortingbution n’est pas une fonction const, ce n’est donc pas possible.

Ma question est la suivante: pour s’assurer qu’il n’y a pas d’état caché dans la dissortingbution, est-il 1) nécessaire et 2) suffisant pour appeler reset() sur la dissortingbution à chaque fois? Par exemple:

 double normal(double mean, double sd, std::mt19937_64& generator) { static std::normal_dissortingbution dist; dist.reset(); return dist(generator, std::normal_dissortingbution::param_type(mean, sd)); } 

(Dans l’ensemble, je ne comprends pas très bien l’objective de la fonction reset() pour les dissortingbutions aléatoires … Je comprends pourquoi le générateur doit parfois être réinitialisé / réensemencé, mais pourquoi l’object de dissortingbution doit-il être réinitialisé?)

Pour s’assurer qu’il n’y a pas d’état caché dans la dissortingbution, est-il 1) nécessaire

Oui.

et 2) suffisant pour appeler reset () sur la dissortingbution à chaque fois?

Oui.

Vous ne voulez probablement pas faire cela cependant. Du moins pas à chaque appel. std::normal_dissortingbution est l’affiche pour permettre aux dissortingbutions de maintenir l’état. Par exemple, une implémentation répandue utilisera la transformation Box-Muller pour calculer deux nombres aléatoires à la fois, mais ne vous en rendra qu’un, en enregistrant l’autre pour votre prochain appel. En appelant reset() avant le prochain appel, la dissortingbution rejetterait ce résultat déjà valide et réduirait de moitié l’efficacité de l’algorithme.

Certaines dissortingbutions ont un état interne. Si vous interférez avec le fonctionnement de la dissortingbution en le réinitialisant constamment, vous n’obtiendrez pas des résultats correctement dissortingbués. C’est comme si vous srand() avant chaque appel à rand() .

L’appel de reset() sur un object de dissortingbution d a l’effet suivant:

Les utilisations ultérieures de d ne dépendent pas des valeurs produites par un moteur avant d’appeler la réinitialisation.

(un moteur est en bref un générateur qui peut être ensemencé).

En d’autres termes, cela efface toutes les données aléatoires “mises en cache” que l’object de dissortingbution a stockées et qui dépendent de la sortie qu’il a précédemment extraite d’un moteur.

Donc, si vous voulez le faire, vous devez appeler reset() . La raison principale pour laquelle je peux penser à ce que vous voudriez faire est que vous assignez à votre moteur une valeur connue dans le but de produire des résultats pseudo-aléatoires reproductibles. Si vous souhaitez que les résultats de votre object de dissortingbution soient également reproductibles en fonction de cette valeur de départ, vous devez réinitialiser l’object de dissortingbution (ou en créer un nouveau).

Une autre raison à laquelle je peux penser est que vous réamorcez de manière défensive l’object générateur, car vous craignez qu’un attaquant ne connaisse partiellement son état interne (comme Fortuna, par exemple). Pour simplifier à l’excès, vous pouvez imaginer que la qualité / sécurité des données du générateur diminue avec le temps et que le réensemencement le restaure. Puisqu’un object de dissortingbution peut mettre en cache des quantités arbitraires de données provenant du générateur, il y aura un délai arbitraire entre l’augmentation de la qualité / sécurité de la sortie du générateur et l’augmentation de la qualité / sécurité de la sortie de l’object de dissortingbution. L’appel de reset sur l’object de dissortingbution évite ce délai. Mais je ne jurerai pas que cette dernière utilisation soit correcte, car elle m’empêche de ne pas me faire mon propre jugement sur ce qui est sécurisé, si je peux éventuellement m’appuyer sur des travaux évalués par des pairs et menés par un expert 🙂

En ce qui concerne votre code en particulier – si vous ne voulez pas que la sortie dépende de l’utilisation précédente du même object dist avec des objects générateurs différents, l’appel à reset() serait le moyen de le faire. Mais je pense qu’il est peu probable que l’appel d’un reset sur un object de dissortingbution, puis son utilisation avec de nouveaux parameters, soient moins coûteux que la construction d’un nouvel object de dissortingbution avec ces parameters. Donc, utiliser un object local static me semble rendre votre fonction non thread-safe sans aucun avantage: vous pouvez créer un nouvel object de dissortingbution à chaque fois et le code ne serait probablement pas pire. Il existe des raisons pour la conception dans la norme, et vous êtes censé utiliser un object de dissortingbution à plusieurs resockets avec le même générateur. La fonction que vous avez écrite, qui consiste à couper l’object de dissortingbution en dehors de l’interface, annule les avantages de cette partie de la conception dans la norme.