Générer efficacement des nombres aléatoires à intervalle ouvert-ouvert (0,1)

Je cherche un moyen efficace de générer des nombres à virgule flottante aléatoires sur l’intervalle ouvert-ouvert (0,1). J’ai actuellement un RNG qui génère des entiers aléatoires sur l’intervalle fermé-fermé de [0, (2 ^ 32) -1]. J’ai déjà créé un RNG à virgule flottante semi-ouvert sur l’intervalle [0,1) en multipliant simplement mon résultat du nombre entier RNG par 1 / ((2 ^ 32) -1) au lieu de le diviser par (2 ^ 32) -1 car c’est inefficace.

Je suis en train de générer des nombres sur l’intervalle (0,1) avec une instruction conditionnelle comme celle ci-dessous:

float open_open_flt = (closed_open_flt==0) ? closed_open_flt : FLT_MIN; 

Malheureusement, ceci est plutôt inefficace puisqu’il s’agit d’un code de contrôle et j’ai l’impression qu’il introduit un biais.

Quelqu’un peut-il suggérer une alternative?

Vous êtes déjà là.

La plus petite distance entre deux flotteurs produits par votre générateur actuel est 1 / (2 ^ 32).

Ainsi, votre générateur produit effectivement [0,1-1 / (2 ^ 32)] .

1 / (2 ^ 32) est supérieur à FLT_MIN.

Ainsi, si vous ajoutez FLT_MIN à votre générateur,

 float open_open_flt = FLT_MIN + closed_open_flt; 

vous aurez [FLT_MIN, 1- (1 / (2 ^ 32)) + FLT_MIN] , qui fonctionne comme un générateur (0,1) .

Étant donné que la probabilité d’observer réellement la probabilité 0 est très faible et que vérifier si un nombre est égal à 0 est le moins coûteux (par rapport à l’addition ou à la multiplication), je régénérerais le nombre aléatoire de manière répétée jusqu’à ce qu’il ne soit pas égal à 0.

Étant donné un échantillon x sélectionné au hasard parmi [0, 2 32 ), je propose d’utiliser:

 0x1.fffffep-32 * x + 0x1p-25 

Raisonnement:

  • Ces valeurs sont telles que le x le plus élevé produit un peu moins de 1-2 -25 avant l’arrondi; il est donc arrondi au float le plus grand inférieur à 1, ce qui correspond à 1-2 -24 . Si nous le rendions plus grand, certaines valeurs seraient arrondies à 1, ce que nous ne voulons pas. Si nous le rendions plus petit, moins de valeurs seraient arrondies à 1-2 -24 , il serait donc moins représenté que nous le souhaitons (plus à ce sujet plus bas).
  • Les valeurs sont telles que le x le plus bas produit 2-25 . Cela produit une certaine symésortinge: la dissortingbution est obligée de s’arrêter du côté supérieur 1-2-26 avant d’arrondir, comme expliqué ci-dessus, nous la rendons donc symésortingque du côté inférieur en nous arrêtant à 0 + 2-25 . Dans une certaine mesure, c’est comme si nous regroupions la droite numérique dans des groupes de largeur 2 – 24 , puis retirions les groupes centrés sur 0 et 1 (qui s’étendent de 2 à 25 de chaque côté de ces nombres).
  • Chaque groupe que nous conservons contient à peu près le même nombre d’échantillons. Cependant, différentes valeurs de float apparaissent dans les bacs, car la résolution de float varie. Il est plus fin près de 0 et plus grossier près de 1. Avec cet agencement, chaque bac est à peu près uniformément représenté, mais les bacs inférieurs auront plus d’échantillons avec une probabilité moindre chacun. La dissortingbution globale rest uniforme.
  • Nous pourrions étendre le bas pour qu’il soit plus proche de zéro. Mais alors, pour la plupart des d (0, ½), il y aurait plus d’échantillons dans (0, d ) que dans (1- d , 1), de sorte que la dissortingbution serait asymésortingque.

Comme vous pouvez le constater, le format à virgule flottante force certaines irrégularités dans une dissortingbution de 0 à 1. Cette question a été soulevée dans d’autres questions relatives au débordement de stack, mais n’a jamais fait l’object d’une discussion approfondie, à ma connaissance. Si vous souhaitez laisser ces irrégularités de la manière décrite ci-dessus, cela dépend de votre demande.

Variations potentielles:

  • Quantifiez tous les échantillons de manière à ce qu’ils apparaissent à des intervalles réguliers, de 2 à 24 , plutôt que d’être plus précis lorsque le format float est plus fin.
  • Autorisez les valeurs plus proches de 1 avant d’arrondir mais convertissez-les en 1-2 -24 après arrondi et abaissez le point final du bas pour faire correspondre. Cela réduit les segments exclus autour de 0 et d’environ 1, au désortingment de l’augmentation du nombre de valeurs regroupées en 1-2 -24, car la résolution n’est pas assez fine pour permettre une meilleure distinction.
  • Passez en double . Il existe ensuite une carte 1-1 des valeurs x origine aux valeurs à virgule flottante, et vous pouvez probablement vous rapprocher de 0 et de 1 si vous le souhaitez.

De plus, contrairement à la réponse d’ ElKamina , la comparaison en virgule flottante (même à zéro) n’est généralement pas plus rapide que l’addition. La comparaison nécessite une ramification sur le résultat, ce qui est un problème dans de nombreux processeurs modernes.

Je cherche un moyen efficace de générer des nombres à virgule flottante aléatoires sur l’intervalle ouvert-ouvert (0,1). J’ai actuellement un RNG qui génère des entiers aléatoires sur l’intervalle fermé-fermé de [0, (2 ^ 32) -1]. J’ai déjà créé un RNG à virgule flottante semi-ouvert sur l’intervalle [0,1) en multipliant simplement mon résultat à partir de l’entier RNG par 1 / ((2 ^ 32) -1)

Cela signifie que votre générateur “essaie” de produire 2 ^ 32 valeurs différentes. Le problème est que le type float a une longueur de 4 octets, ce qui donne moins de 2 ^ 32 valeurs définies globalement. Pour être précis, il ne peut y avoir que 2 ^ 23 valeurs sur l’intervalle [1/2, 1). En fonction de vos besoins, cela peut poser problème ou non.

Vous voudrez peut-être utiliser le générateur de Fibonacci en retard ( wiki ) avec itération formule d'itération de wiki russe
Cela produit déjà des nombres de [0,1), étant donné que les valeurs initiales appartiennent à cet intervalle et peuvent être suffisantes pour vos besoins.