私はいつも、乱数は0と1の間にあり、なし1
であると考えていました。つまり、乱数は半開区間[0,1)からの数値です。これはcppreference.comのドキュメントでstd::generate_canonical
確認できます。
ただし、次のプログラムを実行すると、
#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;
}
それは私に次の出力を与えます:
Bug!
つまり1
、MC統合で問題を引き起こす完璧なを生成します。それは有効な動作ですか、それとも私の側にエラーがありますか?これにより、G ++ 4.7.3でも同じ出力が得られます
g++ -std=c++11 test.c && ./a.out
およびclang 3.3
clang++ -stdlib=libc++ -std=c++11 test.c && ./a.out
これが正しい動作である場合、どうすれば回避でき1
ますか?
編集1:gitのG ++でも同じ問題が発生するようです。私はついています
commit baf369d7a57fb4d0d5897b02549c3517bb8800fd
Date: Mon Sep 1 08:26:51 2014 +0000
でコンパイルすると~/temp/prefix/bin/c++ -std=c++11 -Wl,-rpath,/home/cschwan/temp/prefix/lib64 test.c && ./a.out
同じ出力がldd
得られます
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)
編集2:私はここで動作を報告しました:https://gcc.gnu.org/bugzilla/show_bug.cgi?id = 63176
編集3:clangチームは問題を認識しているようです:http : //llvm.org/bugs/show_bug.cgi?id=18767
abs(random - 1.f) < numeric_limits<float>::epsilon
は、結果が1.0に近いかどうかを確認しますが、これはこのコンテキストでは完全に間違っています。1.0に近い数値、つまり、1.0未満のすべての数値がここで有効です。
1.f == 1.f
すべてのケースで(すべてのケースは何ですか?に変数が表示されていません1.f == 1.f
。ここには1つのケースしかありません。1.f == 1.f
それは常にですtrue
)。この神話をこれ以上広めないでください。浮動小数点の比較は常に正確です。