J'ai toujours pensé que les nombres aléatoires se situeraient entre zéro et un, sans1
, c'est-à-dire que ce sont des nombres de l'intervalle semi-ouvert [0,1). La documentation sur cppreference.com de le std::generate_canonical
confirme.
Cependant, lorsque j'exécute le programme suivant:
#include <iostream>
#include <limits>
#include <random>
int main()
{
std::mt19937 rng;
std::seed_seq sequence{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
rng.seed(sequence);
rng.discard(12 * 629143 + 6);
float random = std::generate_canonical<float,
std::numeric_limits<float>::digits>(rng);
if (random == 1.0f)
{
std::cout << "Bug!\n";
}
return 0;
}
Cela me donne le résultat suivant:
Bug!
c'est à dire qu'il me génère un parfait 1
, ce qui pose des problèmes dans mon intégration MC. Est-ce un comportement valable ou y a-t-il une erreur de mon côté? Cela donne la même sortie avec G ++ 4.7.3
g++ -std=c++11 test.c && ./a.out
et clang 3.3
clang++ -stdlib=libc++ -std=c++11 test.c && ./a.out
Si c'est un comportement correct, comment puis-je éviter 1
?
Edit 1 : G ++ de git semble souffrir du même problème. Je suis sur
commit baf369d7a57fb4d0d5897b02549c3517bb8800fd
Date: Mon Sep 1 08:26:51 2014 +0000
et compiler avec ~/temp/prefix/bin/c++ -std=c++11 -Wl,-rpath,/home/cschwan/temp/prefix/lib64 test.c && ./a.out
donne le même résultat, ldd
donne
linux-vdso.so.1 (0x00007fff39d0d000)
libstdc++.so.6 => /home/cschwan/temp/prefix/lib64/libstdc++.so.6 (0x00007f123d785000)
libm.so.6 => /lib64/libm.so.6 (0x000000317ea00000)
libgcc_s.so.1 => /home/cschwan/temp/prefix/lib64/libgcc_s.so.1 (0x00007f123d54e000)
libc.so.6 => /lib64/libc.so.6 (0x000000317e600000)
/lib64/ld-linux-x86-64.so.2 (0x000000317e200000)
Edit 2 : J'ai signalé le comportement ici: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63176
Edit 3 : L'équipe Clang semble être consciente du problème: http://llvm.org/bugs/show_bug.cgi?id=18767
abs(random - 1.f) < numeric_limits<float>::epsilon
vérifie si le résultat est proche de 1.0 , ce qui est totalement faux dans ce contexte: il y a des nombres proches de 1.0 qui sont des résultats valides ici, à savoir, tous ceux qui sont inférieurs à 1.0.
1.f == 1.f
dans tous les cas (quels sont tous les cas? Je n'ai même pas vu de variables dans1.f == 1.f
; il n'y a qu'un seul cas ici :,1.f == 1.f
et c'est invariablementtrue
). Veuillez ne pas répandre ce mythe plus loin. Les comparaisons en virgule flottante sont toujours exactes.