[解決済み] std::generate_canonicalの出力は1.0が有効か?
質問
乱数は0と1の間にあるとばかり思っていたのですが、実際はどうなのでしょうか?
がなく
1
すなわち、それらは半開放区間[0,1]からの数である。また
のドキュメントを参照してください。
の
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
どのように解決するのですか?
この問題は
std::mt19937
(
std::uint_fast32_t
) から
float
現在の IEEE754 丸めモードが round-to-negative-infinity 以外の場合 (デフォルトは round-to-nearest であることに注意)、精度の損失が発生すると、この標準によって記述されたアルゴリズムは正しくない結果 (アルゴリズムの出力に関する記述と一致しない) を出力します。
mt19937の7549723番目の出力は、あなたのシードで4294967257です(
0xffffffd9u
) で、これを 32 ビット浮動小数点に丸めると
0x1p+32
となり、これは mt19937 の最大値 4294967295 に等しい (
0xffffffffu
) に等しく、これも32ビット浮動小数点に丸められたときです。
規格は、URNG の出力から変換する際に
RealType
の
generate_canonical
の場合、負の無限大に丸めることになるので、この場合は正しい結果になります。 QOIとして、この変更を行うことはlibstdc++にとって良いことでしょう。
この変更で
1.0
は生成されなくなり、代わりに境界値
0x1.fffffep-N
に対して
0 < N <= 8
はより頻繁に生成されます(約
2^(8 - N - 32)
につき
N
MT19937の実際の分布に依存します)。
を使用しないことをお勧めします。
float
と
std::generate_canonical
で直接生成します。
double
で数を生成し、負の無限大に向かって丸めます。
double rd = std::generate_canonical<double,
std::numeric_limits<float>::digits>(rng);
float rf = rd;
if (rf > rd) {
rf = std::nextafter(rf, -std::numeric_limits<float>::infinity());
}
この問題は
std::uniform_real_distribution<float>
でも発生する可能性があります。
double
で負の無限大に丸めることです。
float
.
関連
-
[解決済み】C++でint型に無限大を設定する
-
[解決済み】文字列関数で'char const*'のインスタンスを投げた後に呼び出されるterminate [閉店].
-
[解決済み] 式はクラス型を持つ必要があります。
-
[解決済み】Eclipse IDEでC++エラー「nullptrはこのスコープで宣言されていません」が発生する件
-
[解決済み] using namespace std;」はなぜバッドプラクティスだと言われるのですか?
-
[解決済み] リストからランダムに項目を選択するにはどうすればよいですか?
-
[解決済み] なぜC++はPythonよりもstdinからの行の読み込みが遅いのですか?
-
[解決済み] JavaScript の配列からランダムな値を取得する
-
[解決済み] std::move()とは何ですか?また、どのような場合に使用するのですか?
-
[解決済み] const std::string & をパラメータとして渡す時代は終わったのでしょうか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】C++ 非推奨の文字列定数から「char*」への変換について
-
[解決済み】 != と =! の違いと例(C++の場合)
-
[解決済み] error: 'if' の前に unqualified-id を期待した。
-
[解決済み】エラー:strcpyがこのスコープで宣言されていない
-
[解決済み】c++でstd::vectorを返すための効率的な方法
-
[解決済み】エラー。switchステートメントでcaseラベルにジャンプする
-
[解決済み】システムが指定されたファイルを見つけられませんでした。
-
[解決済み】クラスのコンストラクタへの未定義参照、.cppファイルの修正も含む
-
[解決済み] to_string は std のメンバーではない、と g++ が言っている (mingw)
-
[解決済み】システムが指定されたファイルを見つけられませんでした。