プログラミング言語間で同じ乱数列を使う


プログラミング言語間で同じ乱数列を使う

異なるプログラミング言語で, 同じ乱数列を使いたいときのメモ.

仕組み

  1. 乱数を返すようなスクリプト/実行ファイルrandomを用意しておく.
  2. プログラミング言語から, シェルコマンドとしてrandomを実行し, その結果の文字列を受け取る.
  3. 受け取った文字列を配列/リストに変換する.

乱数を返すプログラムの準備

シェルスクリプトでも良いが, シェルの乱数はいろいろ自由度が低いため, ここではC++で実装する.

random.cpp
// g++ random.cpp -o random
#include <iostream>
#include <vector>
#include <numeric>
#include <algorithm>

using namespace std;

int main(int argc, char **argv){
    if (argc!=3){
        cerr<<"Error: ./random seed max"<<endl;
        return 1;
    }
    srand(atoi(argv[1]));
    int n=atoi(argv[2]);
    std::vector<int> idx(n);
    std::iota(idx.begin(), idx.end(), 0);
    std::random_shuffle(idx.begin(), idx.end());
    for (int i : idx)
      cout<<i<<" ";
    return 0;
}

g++ random.cpp -o randomでコンパイルしておこう.
(Versionが古いと-std=c++11が必要な場合もある.)
このプログラムは, 重複なし0-(n-1)のランダム列を返す.
使い方: ./random seed n

$ ./random 1 10
4 3 7 8 0 5 2 1 6 9

※これをC++で実装した場合は, C++からあえてrandomを呼ぶ必要はありませんが, C++からシェルコマンドの実行結果を取得したいことはあると思うため以下を記述.

言語からシェルコマンドの実行

以下では, 実行したいコマンドを./random 1 10として書いていく.
この結果の標準出力が文字列として返ってくるような関数を使っていく.

Python

import subprocess
result = subprocess.getoutput('./random 1 10')

Matlab

[~,result] = unix('./random 1 10')
  • 第一戻り値は, 終了コードが返ってくる

C++

実行するだけでいいならsystem()でいいが, 今回は標準出力結果がほしいため, 自分で実装してやる必要がある.


#include <array>
#include <cstdio>
#include <iostream>
#include <string>

using namespace std;

std::string exec_cmd(const char* cmd) {
    FILE *fp;
    if ((fp = popen(cmd,"r")) == nullptr)
        return "";
    std::string result;
    std::array<char, 256> buf;
    while (!feof(fp))
        if (fgets(buf.data(), buf.size(), fp) != nullptr)
            result += buf.data();
    return result;
}

int main(){
    string result = exec_cmd("./random 1 10");
    cout<<result<<endl;
    return 0;
}

文字列から配列/リストへ

resultに入った文字列を配列/リストへ変換する.

Python

result = [int(i) for i in result.strip().split()]

Matlab

result = str2num(result)

C++

こっちも自分で作らないといけない.

#include <sstream>
#include <istream>
#include <vector>

using namespace std;

vector<int> str2int(const string &str){
  vector<int> vec;
  stringstream ss(str);
  string buf;

  while (getline(ss, buf, ' '))
    if (!buf.empty())
      vec.push_back(atoi(buf.c_str()));
  return vec;
}

呼び出し側: vector<int> int_array = str2int(result)