このブログを検索

2019年9月29日日曜日

【C++】 WAVEファイル作成

【C++】 WAVEファイル作成
(2019年9月29日)


■使用ソフト
・Visual Studio Community 2019


■言語
・C/C++


■Windows SDK バージョン
・10.0.17763.0
 ※Windows SDK バージョンの変更方法


■手順
1.コンソールアプリを作成する。
新しいプロジェクトの作成→コンソールアプリ→プロジェクト名と場所を指定して作成

2.C++ファイル(.cpp)を以下のとおり変更する。
コード非公開(後日公開予定)

3.実行結果
1秒間のC5(ド)の音のWAVEファイルが作成される(c5.wav)

4.参考文献
音ファイル(拡張子:WAVファイル)のデータ構造について

サウンドプログラミング入門

2019年9月22日日曜日

【C++】 ディープラーニング

【C++】  ディープラーニング
(2019年9月22日)


■使用ソフト
・Visual Studio Community 2019


■言語
・C/C++


■Windows SDK バージョン
・10.0.17763.0
 ※Windows SDK バージョンの変更方法


■使用ライブラリ
・Eigen 3.3.7
 ※Eigen行列計算ライブラリ導入方法


■手順
1.http://yann.lecun.com/exdb/mnist/で以下のファイルをダウンロードし解凍しておく。
train-images-idx3-ubyte.gz
train-labels-idx1-ubyte.gz
t10k-images-idx3-ubyte.gz
t10k-labels-idx1-ubyte.gz

2.コンソールアプリを作成する。
新しいプロジェクトの作成→コンソールアプリ→プロジェクト名と場所を指定して作成

3.プロジェクトフォルダに1.で解凍したファイルを入れる。

4.C++ファイル(.cpp)を以下のとおり変更する。
コード非公開(後日公開予定)

5.実行結果
【Releaseモード(x64)で実行】
※プロジェクト右クリック→プロパティ→C/C++→「拡張命令セットを有効にする」をAVX2にした場合
正解率 96.57%
処理時間 305.191秒


6.参考文献
MNISTのデータファイルをC言語で読み込む

MNISTデータを読み込むプログラム(C++)

最短コースでわかる ディープラーニングの数学

2019年9月15日日曜日

【C++】 Eigen行列計算2

【C++】 Eigen行列計算2
(2019年9月15日)


■使用ソフト
・Visual Studio Community 2019


■言語
・C/C++


■Windows SDK バージョン
・10.0.17763.0
 ※Windows SDK バージョンの変更方法


■使用ライブラリ
・Eigen 3.3.7
 ※Eigen行列計算ライブラリ導入方法


■手順
1.コンソールアプリを作成する。
新しいプロジェクトの作成→コンソールアプリ→プロジェクト名と場所を指定して作成

2.C++ファイル(.cpp)を以下のとおり変更する。
#include <iostream>
#include <Eigen/Core>

int main()
{
    //mat1
    Eigen::MatrixXd mat1(3, 5);
    for (int i = 0; i < mat1.rows(); i++)
    {
        for (int j = 0; j < mat1.cols(); j++)
        {
            mat1(i, j) = (double)i + (double)j;
        }
    }
    std::cout << mat1 << std::endl;

    std::cout << "-------------------------------------------------------------" << std::endl;

    //vec1
    Eigen::VectorXd vec1 = Eigen::VectorXd::LinSpaced(5, 1, 5);
    std::cout << vec1 << std::endl;

    std::cout << "-------------------------------------------------------------" << std::endl;

    //sin(cos, exp, logも同様に演算可能)
    std::cout << mat1.array().sin() << std::endl;

    std::cout << "-------------------------------------------------------------" << std::endl;

    //行列からベクトルを減算
    std::cout << mat1.rowwise() - vec1.transpose() << std::endl;

    std::cout << "-------------------------------------------------------------" << std::endl;

    //全ての要素の和(sum)、積(prod)、平均(mean)、最大(maxCoeff)、最小(minCoeff)
    std::cout << mat1.sum() << "," << mat1.prod() << "," << mat1.mean() << ","
        << mat1.maxCoeff() << "," << mat1.minCoeff() << std::endl;

    std::cout << "-------------------------------------------------------------" << std::endl;

    //行ごとの和(sum) 積(prod)、平均(mean)、最大(maxCoeff)、最小(minCoeff)も同様
    std::cout << mat1.rowwise().sum() << std::endl;

    std::cout << "-------------------------------------------------------------" << std::endl;

    //列ごとの和(sum) 積(prod)、平均(mean)、最大(maxCoeff)、最小(minCoeff)も同様
    std::cout << mat1.colwise().sum() << std::endl;

    std::cout << "-------------------------------------------------------------" << std::endl;

    //行の参照(row) 列の参照(col)も同様
    std::cout << mat1.row(2) << std::endl;

    std::cout << "-------------------------------------------------------------" << std::endl;

    //ブロック参照(1行3列目から2x2行列を抜き出し)
    std::cout << mat1.block(1, 3, 2, 2) << std::endl;

    std::cout << "-------------------------------------------------------------" << std::endl;

    //3x7行列にリサイズ(追加した列は0で初期化)
    mat1.conservativeResizeLike(Eigen::MatrixXd::Zero(3, 7));
    std::cout << mat1 << std::endl;

    std::cout << "-------------------------------------------------------------" << std::endl;

    //mat2の1番右の列からmat1の列数(7列)に、mat1全てを代入する
    Eigen::MatrixXd mat2 = Eigen::MatrixXd::Ones(3, 8);//全て1で初期化
    mat2.rightCols(mat1.cols()) = mat1.rightCols(mat1.cols());
    std::cout << mat2 << std::endl;

    std::cout << "-------------------------------------------------------------" << std::endl;

    return 0;
}

3.実行結果
・sin(cos, exp, logも同様に演算可能)
・行列からベクトルを減算
・全ての要素の和(sum)、積(prod)、平均(mean)、最大(maxCoeff)、最小(minCoeff)
・行ごとの和(sum) 積(prod)、平均(mean)、最大(maxCoeff)、最小(minCoeff)も同様
・列ごとの和(sum) 積(prod)、平均(mean)、最大(maxCoeff)、最小(minCoeff)も同様
・行の参照(row) 列の参照(col)も同様
・ブロック参照(1行3列目から2x2行列を抜き出し)
・3x7行列にリサイズ(追加した列は0で初期化)
・mat2の1番右の列からmat1の列数(7列)に、mat1全てを代入する

4.参考文献
【C++】Eigen関数一覧

Eigen ー C++で線形代数を!(2)

c – 新しい値にゼロ値を指定したconservativeResize()

Is there a way to insert row/column in matrix (Eigen C++)?

【C++】 Eigen行列計算1

【C++】 Eigen行列計算1
(2019年9月15日)


■使用ソフト
・Visual Studio Community 2019


■言語
・C/C++


■Windows SDK バージョン
・10.0.17763.0
 ※Windows SDK バージョンの変更方法


■使用ライブラリ
・Eigen 3.3.7
 ※Eigen行列計算ライブラリ導入方法


■手順
1.コンソールアプリを作成する。
新しいプロジェクトの作成→コンソールアプリ→プロジェクト名と場所を指定して作成

2.C++ファイル(.cpp)を以下のとおり変更する。
#include <iostream>
#include <Eigen/Core>

int main()
{
    //mat1
    Eigen::MatrixXd mat1 = Eigen::MatrixXd::Constant(3, 5, 2);
    std::cout << mat1 << std::endl;

    std::cout << "-------------------------------------------------------------" << std::endl;

    //mat2
    Eigen::MatrixXd mat2 = Eigen::MatrixXd::Constant(5, 3, 4);
    std::cout << mat2 << std::endl;

    std::cout << "-------------------------------------------------------------" << std::endl;

    //mat3
    Eigen::MatrixXd mat3(3, 5);
    for (int i = 0; i < mat3.rows(); i++)
    {
        for (int j = 0; j < mat3.cols(); j++)
        {
            mat3(i, j) = (double)i + (double)j;
        }
    }
    std::cout << mat3 << std::endl;

    std::cout << "-------------------------------------------------------------" << std::endl;

    //行列と行列の和
    std::cout << mat1 + mat3 << std::endl;

    std::cout << "-------------------------------------------------------------" << std::endl;

    //行列と行列の積
    std::cout << mat1 * mat2 << std::endl;

    std::cout << "-------------------------------------------------------------" << std::endl;

    //行列とスカラーの積
    std::cout << mat1 * 3 << std::endl;

    std::cout << "-------------------------------------------------------------" << std::endl;

    //行列とスカラーの商
    std::cout << mat1 / 2 << std::endl;

    std::cout << "-------------------------------------------------------------" << std::endl;

    //行列と行列の要素同士の積
    std::cout << mat1.array() * mat3.array() << std::endl;

    std::cout << "-------------------------------------------------------------" << std::endl;

    //転置行列
    std::cout << mat2.transpose() << std::endl;

    std::cout << "-------------------------------------------------------------" << std::endl;

    //逆行列
    std::cout << mat1.array().inverse() << std::endl;

    std::cout << "-------------------------------------------------------------" << std::endl;

    return 0;
}

3.実行結果
・行列と行列の和
・行列と行列の積
・行列とスカラーの積
・行列とスカラーの商
・行列と行列の要素同士の積
・転置行列
・逆行列

4.参考文献
Eigen - C++で使える線形代数ライブラリ

【C++】Eigen関数一覧

Eigen ー C++で線形代数を!(2)

【C++】 Eigenベクトルの初期化

【C++】 Eigenベクトルの初期化
(2019年9月15日)


■使用ソフト
・Visual Studio Community 2019


■言語
・C/C++


■Windows SDK バージョン
・10.0.17763.0
 ※Windows SDK バージョンの変更方法


■使用ライブラリ
・Eigen 3.3.7
 ※Eigen行列計算ライブラリ導入方法


■手順
1.コンソールアプリを作成する。
新しいプロジェクトの作成→コンソールアプリ→プロジェクト名と場所を指定して作成

2.C++ファイル(.cpp)を以下のとおり変更する。
#include <iostream>
#include <Eigen/Core>
#include <random>

int main()
{
    //全ての値が0のベクトル
    Eigen::VectorXd vec1 = Eigen::VectorXd::Zero(5);
    std::cout << vec1 << std::endl;

    std::cout << "-------------------------------------------------------------" << std::endl;

    //全ての値が1のベクトル
    Eigen::VectorXd vec2 = Eigen::VectorXd::Ones(5);
    std::cout << vec2 << std::endl;

    std::cout << "-------------------------------------------------------------" << std::endl;

    //全ての値が7のベクトル
    Eigen::VectorXd vec3 = Eigen::VectorXd::Constant(5, 7);
    std::cout << vec3 << std::endl;

    std::cout << "-------------------------------------------------------------" << std::endl;

    //1~2を分割した値
    Eigen::VectorXd vec4 = Eigen::VectorXd::LinSpaced(5, 1, 2);
    std::cout << vec4 << std::endl;

    std::cout << "-------------------------------------------------------------" << std::endl;

    //1番目のみ1で、それ以外が0
    Eigen::VectorXd vec5 = Eigen::VectorXd::Unit(5, 1);
    std::cout << vec5 << std::endl;

    std::cout << "-------------------------------------------------------------" << std::endl;

    //全ての値が乱数のベクトル(範囲-1.0~1.0)
    Eigen::VectorXd vec6 = Eigen::VectorXd::Random(5);
    std::cout << vec6 << std::endl;

    std::cout << "-------------------------------------------------------------" << std::endl;

    //任意の乱数のベクトル(int型)
    std::random_device seed;
    std::mt19937 random(seed());
    std::uniform_int_distribution<> number(1, 6);//int型の1~6の乱数
    Eigen::VectorXd vec7 = Eigen::VectorXd::Zero(5).unaryExpr([&](double dummy) {return number(random); });
    std::cout << vec7 << std::endl;

    std::cout << "-------------------------------------------------------------" << std::endl;

    //任意の乱数のベクトル(double型)
    std::random_device seed2;
    std::mt19937 random2(seed2());
    std::uniform_real_distribution<> number2(1, 6);//double型の1~6の乱数
    Eigen::VectorXd vec8 = Eigen::VectorXd::Zero(5).unaryExpr([&](double dummy) {return number2(random2); });
    std::cout << vec8 << std::endl;

    std::cout << "-------------------------------------------------------------" << std::endl;

    //要素の直接参照
    Eigen::VectorXd vec9(5);
    for (int i = 0; i < vec8.rows(); i++)
    {
        vec9(i) = i * i;
    }
    std::cout << vec9 << std::endl;

    std::cout << "-------------------------------------------------------------" << std::endl;

    return 0;
}

3.実行結果
・全ての値が0のベクトル
・全ての値が1のベクトル
・全ての値が7のベクトル
・1~2を分割した値
・1番目のみ1で、それ以外が0
・全ての値が乱数のベクトル(範囲-1.0~1.0)
・任意の乱数のベクトル(int型)
・任意の乱数のベクトル(double型)
・要素の直接参照

4.参考文献
The Matrix class

【C++】Eigen関数一覧

Eigen ー C++で線形代数を!(2)

【C++】 Eigen行列の初期化

【C++】 Eigen行列の初期化
(2019年9月15日)


■使用ソフト
・Visual Studio Community 2019


■言語
・C/C++


■Windows SDK バージョン
・10.0.17763.0
 ※Windows SDK バージョンの変更方法


■使用ライブラリ
・Eigen 3.3.7
 ※Eigen行列計算ライブラリ導入方法


■手順
1.コンソールアプリを作成する。
新しいプロジェクトの作成→コンソールアプリ→プロジェクト名と場所を指定して作成

2.C++ファイル(.cpp)を以下のとおり変更する。
#include <iostream>
#include <Eigen/Core>
#include <random>

int main()
{
    //全ての値が0の3x5行列
    Eigen::MatrixXd mat1 = Eigen::MatrixXd::Zero(3, 5);
    std::cout << mat1 << std::endl;

    std::cout << "-------------------------------------------------------------" << std::endl;

    //全ての値が1の3x5行列
    Eigen::MatrixXd mat2 = Eigen::MatrixXd::Ones(3, 5);
    std::cout << mat2 << std::endl;

    std::cout << "-------------------------------------------------------------" << std::endl;

    //全ての値が7の3x5行列
    Eigen::MatrixXd mat3 = Eigen::MatrixXd::Constant(3, 5, 7);
    std::cout << mat3 << std::endl;

    std::cout << "-------------------------------------------------------------" << std::endl;

    //5x5の単位行列
    Eigen::MatrixXd mat4 = Eigen::MatrixXd::Identity(5, 5);
    std::cout << mat4 << std::endl;

    std::cout << "-------------------------------------------------------------" << std::endl;

    //全ての値が乱数の3x5行列(範囲-1.0~1.0)
    Eigen::MatrixXd mat5 = Eigen::MatrixXd::Random(3, 5);
    std::cout << mat5 << std::endl;

    std::cout << "-------------------------------------------------------------" << std::endl;

    //任意の乱数の3x5行列(int型)
    std::random_device seed;
    std::mt19937 random(seed());
    std::uniform_int_distribution<> number(1, 6);//int型の1~6の乱数
    Eigen::MatrixXd mat6 = Eigen::MatrixXd::Zero(3, 5).unaryExpr([&](double dummy) {return number(random); });
    std::cout << mat6 << std::endl;

    std::cout << "-------------------------------------------------------------" << std::endl;

    //任意の乱数の3x5行列(double型)
    std::random_device seed2;
    std::mt19937 random2(seed2());
    std::uniform_real_distribution<> number2(1, 6);//double型の1~6の乱数
    Eigen::MatrixXd mat7 = Eigen::MatrixXd::Zero(3, 5).unaryExpr([&](double dummy) {return number2(random2); });
    std::cout << mat7 << std::endl;

    std::cout << "-------------------------------------------------------------" << std::endl;

    //要素の直接参照
    Eigen::MatrixXd mat8(3, 5);
    for (int i = 0; i < mat8.rows(); i++)
    {
        for (int j = 0; j < mat8.cols(); j++)
        {
            mat8(i, j) = i + j;
        }
    }
    std::cout << mat8 << std::endl;

    std::cout << "-------------------------------------------------------------" << std::endl;

    return 0;
}

3.実行結果
・全ての値が0の3x5行列
・全ての値が1の3x5行列
・全ての値が7の3x5行列
・5x5の単位行列
・全ての値が乱数の3x5行列(範囲-1.0~1.0)
・任意の乱数の3x5行列(int型)
・任意の乱数の3x5行列(double型)
・要素の直接参照

4.参考文献
ベクトル/行列演算の定番ライブラリEigen

【C++】Eigen関数一覧

Eigen ー C++で線形代数を!(2)

Eigen matrix library filling a matrix with random float values in a given range

2019年9月14日土曜日

【C++】 Eigen行列の積

【C++】 Eigen行列の積
(2019年9月14日)


■使用ソフト
・Visual Studio Community 2019


■言語
・C/C++


■Windows SDK バージョン
・10.0.17763.0
 ※Windows SDK バージョンの変更方法


■使用ライブラリ
・Eigen 3.3.7
 ※Eigen行列計算ライブラリ導入方法


■手順
1.以下をベースにコード変更する。
【C++】 メッセージボックスの作成

2.C++ファイル(.cpp)を以下のとおり変更する。
#include <windows.h>
#include <Eigen/Core>
#include <chrono>
#include <vector>

//------------------------------------------------------------
// MultMtx()関数:行列の積
//------------------------------------------------------------
void MultMtx(std::vector<std::vector<double> >& mtx1, std::vector<std::vector<double> >& mtx2, std::vector<std::vector<double> >& resultMtx)
{
    for (int i = 0; i < (int)mtx1.size(); i++)
    {
        for (int j = 0; j < (int)mtx2[0].size(); j++)
        {
            double sum = 0;
            for (int k = 0; k < (int)mtx2.size(); k++)
            {
                sum += mtx1[i][k] * mtx2[k][j];
            }
            resultMtx[i][j] = sum;
        }
    }
}

//--------------------------------------------------------------------------------------
// wWinMain()関数:エントリーポイント
//--------------------------------------------------------------------------------------
int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow)
{
    WCHAR wcText[256];

    //------------------------------------------------------------
    // Eigenを使用した行列の積
    //------------------------------------------------------------
    auto Start = std::chrono::system_clock::now();//時間計測開始

    Eigen::MatrixXd mat1 = Eigen::MatrixXd::Constant(100, 100, 0.011);
    Eigen::MatrixXd mat2 = Eigen::MatrixXd::Constant(100, 100, 0.011);
    
    for (int i = 0; i < 100; i++)
    {
        mat1 *= mat2;
    }
    
    auto End = std::chrono::system_clock::now();//時間計測終了
    auto Calc = End - Start;
    auto Time = std::chrono::duration_cast<std::chrono::milliseconds>(Calc).count();

    //------------------------------------------------------------
    // std::vectorを使用した行列の積
    //------------------------------------------------------------
    auto Start2 = std::chrono::system_clock::now();//時間計測開始

    std::vector<std::vector<double> > mat3(100, std::vector<double>(100, 0.011));
    std::vector<std::vector<double> > mat4(100, std::vector<double>(100, 0.011));
    std::vector<std::vector<double> > result(100, std::vector<double>(100));
    
    for (int i = 0; i < 100; i++)
    {
        MultMtx(mat3, mat4, result);
        mat3 = result;
    }

    auto End2 = std::chrono::system_clock::now();//時間計測終了
    auto Calc2 = End2 - Start2;
    auto Time2 = std::chrono::duration_cast<std::chrono::milliseconds>(Calc2).count();

    //------------------------------------------------------------
    // 出力
    //------------------------------------------------------------
    swprintf(wcText, 256, L"%lf, %lld, %lf, %lld", mat1(0, 0), Time, mat3[0][0], Time2);

    MessageBox(NULL, wcText, L"Eigen", MB_OK);

    return 0;
}

3.実行結果(Eigenを使用した行列の積とstd::vectorを使用した行列の積の速度比較)
【Debugモードの場合】
・Eigenを使用した行列の積→5.729秒
・std::vectorを使用した行列の積→8.552秒

【Releaseモードの場合】
・Eigenを使用した行列の積→0.025秒
・std::vectorを使用した行列の積→0.09秒

4.参考文献
ベクトル/行列演算の定番ライブラリEigen

【C++】Eigen関数一覧

C言語による標準アルゴリズム辞典

2019年9月13日金曜日

【C++】 Eigen行列計算ライブラリ導入

【C++】 Eigen行列計算ライブラリ導入
(2019年9月13日)


■使用ソフト
・Visual Studio Community 2019


■言語
・C/C++


■Windows SDK バージョン
・10.0.17763.0
 ※Windows SDK バージョンの変更方法


■手順
1.http://eigen.tuxfamily.org/index.php?title=Main_Pageにアクセス
Get itのEigen 3.3.7のzipをクリックしてダウンロード

2.ダウンロードしたzipファイルを解凍し、「Eigen」フォルダをコピー

3.ソリューションエクスプローラーのプロジェクトを右クリック→プロパティ
→「VC++ディレクトリ」→「インクルードディレクトリ」→編集
→「評価された値」に記載のフォルダにアクセスし、2.でコピーしたフォルダをペーストする



2019年9月7日土曜日

【C++】 unordered_mapを使用したFisher-Yates法

【C++】 unordered_mapを使用したFisher-Yates法
(2019年9月7日)


■使用ソフト
・Visual Studio Community 2019


■言語
・C/C++


■Windows SDK バージョン
・10.0.17763.0
 ※Windows SDK バージョンの変更方法


■手順
1.以下をベースにコード変更する。
【C++】 メッセージボックスの作成

2.C++ファイル(.cpp)を以下のとおり変更する。
#include <windows.h>
#include <random>
#include <unordered_map>

int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow)
{
    WCHAR wcText[256];

    int size = 5;
    int randmin = 0;
    int randmax = 9;

    std::vector<int> v;
    v.reserve(size);

    std::random_device seed;
    std::mt19937 random(seed());

    int choice;
    std::unordered_map<int, int> um;
    std::unordered_map<int, int>::iterator itr, max_itr;

    for (int i = 0; i < size; i++)
    {
        choice = std::uniform_int_distribution<int>(randmin, randmax)(random);//randmin~randmaxの中からランダムに1つ数字を選ぶ
        itr = um.find(choice);//選んだ数字がunorderd_mapの1番目の数字の中に登録されているか探す

        if (itr != um.end())//unorderd_mapの中に登録されている場合
        {
            v.push_back(itr->second);//登録されている2番目の数字をvectorに格納
        }
        else//unorderd_mapの中に登録されていない場合
        {
            v.push_back(choice);//選んだ数字をvectorに格納
        }

        if (choice != randmax)//選んだ数字がrandmaxと同じではない場合
        {
            max_itr = um.find(randmax);//randmaxがunorderd_mapの1番目の数字の中に登録さているか探す
            if (max_itr != um.end()) um[choice] = max_itr->second;//randmaxがunorderd_mapに登録されている場合、unorderd_mapに1番目:選んだ数字、2番目:randmaxの2番目の数字を格納
            else um[choice] = randmax;//randmaxがunorderd_mapに登録されていない場合、unorderd_mapに1番目:選んだ数字、2番目:randmaxを格納
        }

        randmax -= 1;//randmaxから1をマイナスする

        //--------------------------------------------------------------------------------
        //●i = 0, randmax = 9
        // 0 1 2 3 4 5 6 7 8 9
        //
        // unorderd_map 空っぽ
        // vector 空っぽ
        //
        // 0~9の中からランダムに1つ数字を選ぶ→4
        // 選んだ数字がunorderd_mapの1番目の数字の中に登録さているか探す→ない
        //  選んだ数字をvectorに格納→v[0] = 4
        // 選んだ数字がrandmaxと同じでない場合→4 != 9
        //  randmaxがunorderd_mapの1番目の数字の中に登録さているか探す→ない
        //  unorderd_mapに1番目:選んだ数字、2番目:randmaxを格納→{4, 9}
        // randmaxから1をマイナスする→randmax = 8
        //
        //●i = 1, randmax = 8
        // 0 1 2 3 4(9) 5 6 7 8
        //
        // unorderd_map {4, 9}
        // vector 4
        //
        // 0~8の中からランダムに1つ数字を選ぶ→4
        // 選んだ数字がunorderd_mapの1番目の数字の中に登録さているか探す→ある{4, 9}
        //  登録されている2番目の数字をvectorに格納→v[1] = 9
        // 選んだ数字がrandmaxと同じではない場合→4 != 8
        //  randmaxがunorderd_mapの1番目の数字の中に登録さているか探す→ない
        //  unorderd_mapに1番目:選んだ数字、2番目:randmaxを格納→{4, 8} ※{4, 9}は{4, 8}に上書きされる
        // randmaxから1をマイナスする→randmax = 7
        //
        //●i = 2, randmax = 7
        // 0 1 2 3 4(8) 5 6 7
        //
        // unorderd_map {4, 8}
        // vector 4, 9
        //
        // 0~7の中からランダムに1つ数字を選ぶ→6
        // 選んだ数字がunorderd_mapの1番目の数字の中に登録さているか探す→ない
        //  選んだ数字をvectorに格納→v[2] = 6
        // 選んだ数字がrandmaxと同じではない場合→6 != 7
        //  randmaxがunorderd_mapの1番目の数字の中に登録さているか探す→ない
        //  unorderd_mapに1番目:選んだ数字、2番目:randmaxを格納→{6, 7}
        // randmaxから1をマイナスする→randmax = 6
        //
        //●i = 3, randmax = 6
        // 0 1 2 3 4(8) 5 6(7)
        //
        // unorderd_map {4, 8}, {6, 7}
        // vector 4, 9, 6
        //
        // 0~6の中からランダムに1つ数字を選ぶ→5
        // 選んだ数字がunorderd_mapの1番目の数字の中に登録さているか探す→ない
        //  選んだ数字をvectorに格納→v[3] = 5
        // 選んだ数字がrandmaxと同じではない場合→5 != 6
        //  randmaxがunorderd_mapの1番目の数字の中に登録さているか探す→ある{6, 7}
        //  unorderd_mapに1番目:選んだ数字、2番目:randmaxの2番目の数字を格納→{5, 7}
        // randmaxから1をマイナスする→randmax = 5
        //
        //●i = 4, randmax = 5
        // 0 1 2 3 4(8) 5(7)
        //
        // unorderd_map {4, 8}, {6, 7}, {5, 7}
        // vector 4, 9, 6, 5
        //
        // 0~5の中からランダムに1つ数字を選ぶ→5
        // 選んだ数字がunorderd_mapの1番目の数字の中に登録さているか探す→ある{5, 7}
        //  登録されている2番目の数字をvectorに格納→v[4] = 7
        // 選んだ数字がrandmaxと同じ→5 == 5
        // randmaxから1をマイナスする→randmax = 4
        //
        //■最終結果(例)
        // vector 4, 9, 6, 5, 7
    }

    swprintf(wcText, 256, L"%d %d %d %d %d", v[0], v[1], v[2], v[3], v[4]);

    MessageBox(NULL, wcText, L"unordered_mapを使用したFisher-Yates法", MB_OK);

    return 0;
}

3.実行結果(0~9までの数字をシャッフルして、最初の5文字を出力する)

4.参考文献
C++で効率よく重複のない乱数列を生成する