1. koyo-miyamura

    Posted

    koyo-miyamura
Changes in title
+[C++] Windows環境でmt19937の初期化にrandom_deviceを使うと実行毎に同じ乱数列が生成される問題
Changes in tags
Changes in body
Source | HTML | Preview
@@ -0,0 +1,90 @@
+# 環境
+* Windows 10
+ * Git Bash
+
+``` bash
+$ bash --version
+GNU bash, version 4.3.42(5)-release (x86_64-pc-msys)
+Copyright (C) 2013 Free Software Foundation, Inc.
+License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
+
+This is free software; you are free to change and redistribute it.
+There is NO WARRANTY, to the extent permitted by law.
+
+```
+
+# 問題
+ある日以下のような手順とC++コードで、[0,2π]の一様乱数を生成しようとした
+
+* `std::random_device`で非決定的な乱数を生成
+* `mt19937`の初期シードに`random_device`で生成した値を入れる
+* **実行毎に別の乱数が生成**
+
+``` C++
+ // この乱数生成器が実行毎に別の乱数を生成するかは環境依存である
+ // Windows環境では実行毎に同じ値を出すので注意
+ // Ubuntuでは実行毎に別の乱数を生成した
+ std::random_device rnd;
+ std::mt19937 mt(rnd());
+
+ std::uniform_real_distribution<double> theta(0.0, 2*M_PI);
+ for(int i = 0; i < 10; i++) std::cout << theta(mt) << std::endl;
+```
+
+以下のようにコンパイルし
+` g++ kadai3.cpp -o kadai3 -std=gnu++11`
+
+実行してみたところ以下のようになった
+![image.png](https://qiita-image-store.s3.amazonaws.com/0/201242/dec0c9fe-6706-fe61-43db-e8e5950b780a.png)
+
+**実行毎に同じ乱数返すじゃん!**
+
+# 原因
+おかしいと思い、調べてみたところ以下のページに
+https://cpprefjp.github.io/reference/random/random_device.html
+
+>Windows版のGCC (MinGW, libstdc++) では、random_deviceクラスは擬似乱数生成器であるmt19937で実装されている。その環境のデフォルトでは固定の乱数列が生成されてしまうので注意すること。コンストラクタの引数としてシード値を文字列化して渡せばmt19937のシードとして扱われるが、非決定論的な乱数として振る舞わないことは変わらない。この環境ではrandom_deviceの使用は推奨しない
+
+>代替
+
+>* クロスプラットフォーム
+ * CPU が提供する RDRAND, RDSEED 命令
+* Windows
+ * rand_s (CryptGenRandom のラッパー)
+ * RtlGenRandom 関数 (替わりに CryptGenRandom を使用することを推奨)
+ * CryptGenRandom 関数
+
+と書いてありました(詳しくはリンク先を参照)
+つまり、Windows環境では上記のコードで「実行毎に別の乱数列」を生成できない模様
+
+# 検証
+## コマンドプロンプトで実行
+コマンドプロンプトのg++(バージョンは以下)でコンパイルし実行しても同じ結果になりました(実行結果は同じなので割愛)
+
+```
+>g++ --version
+g++ (tdm64-1) 5.1.0
+Copyright (C) 2015 Free Software Foundation, Inc.
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+```
+
+## VirtualBoxのUbuntuでコンパイル
+同じWindows環境でVirtualBoxを起動しUbuntu16.04で実行したところ
+
+``` bash
+$ g++ --version
+g++ (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609
+Copyright (C) 2015 Free Software Foundation, Inc.
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+```
+
+![image.png](https://qiita-image-store.s3.amazonaws.com/0/201242/4181cc73-cf8b-2c28-d376-0c76d949e49d.png)
+
+
+と実行毎に別の乱数列が生成とのことで解決です
+
+---
+
+中々目的のページが見つからなくて時間かかったので、誰かのお役に立てればうれしいです