Help us understand the problem. What is going on with this article?

[C++] Windows環境でmt19937の初期化にrandom_deviceを使うと実行毎に同じ乱数列が生成される問題

More than 1 year has passed since last update.

環境

  • Windows 10
    • Git 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.

※コメントをいただいたので追記
今回の問題はWindowsが悪いのではなく、mingwのlibstdc++の実装が原因とのこと
(詳細はコメント欄参照)

問題

ある日以下のような手順とC++コードで、[0,2π]の一様乱数を生成しようとした

  • std::random_deviceで非決定的な乱数を生成
  • mt19937の初期シードにrandom_deviceで生成した値を入れる
  • 実行毎に別の乱数が生成
    // この乱数生成器が実行毎に別の乱数を生成するかは環境依存である
    // 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://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環境ではrandom_deviceが非決定的乱数として実行されないので、上記のコードで「実行毎に別の乱数列」を生成できない模様

検証

コマンドプロンプトで実行

コマンドプロンプトの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で実行したところ

$ 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

と実行毎に別の乱数列が生成とのことで解決です


中々目的のページが見つからなくて時間かかったので、誰かのお役に立てればうれしいです

koyo-miyamura
九州大学大学院システム情報科学府卒 学び続ける癒し系エンジニア note: https://note.mu/m_k9071 ポートフォリオ: https://koyo-miyamura.github.io/portfolio/
http://maple-daily.com/
fukuokaex
エンジニア/企業向けにElixirプロダクト開発・SI案件開発を支援する福岡のコミュニティ
https://fukuokaex.fun/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした