一様乱数と正規乱数

C++11からboostなくてもよくなったんで、使い方メモっておく。正規分布に設定するパラメーターは平均と"標準偏差"であって、"分散"ではない点に注意。
あと、擬似乱数生成器をあえて値渡ししてるんだけど、内部で保有しているとおもわれる乱数の状態もコピーするっぽく、乱数は"seedで指定した値のはじめから"ではなく、"続きから"出てくる点も注意する。

#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <random>

template<class T_>
void show_histgram(T_ & dist, std::mt19937 engine)
{
	//ヒストグラム生成
	std::cout << "======= show histgram =========" << std::endl;
	std::map<int, int> hist;
	for (int n = 0; n < 10000; ++n){ ++hist[std::round(dist(engine))]; }
	for (auto p : hist)
	{
		std::cout << std::fixed << std::setprecision(1) << std::setw(2)
			<< p.first << ' ' << std::string(p.second / 200, '*') << std::endl;
	}
}
template<class T_>
void show_value(T_ & dist, std::mt19937 engine, int n)
{
	//値表示
	std::cout << "======= show values =========" << std::endl;
	for(int i = 0; i < n; ++i){ std::cout << dist(engine) << std::endl; }
}
int main()
{
	//シードを100に固定したメルセンヌ・ツイスター乱数生成器
	std::mt19937 engine(100);

	// 平均0, "標準偏差"2の正規分布 & 一様分布
	std::normal_distribution<> normal(0, 2);
	std::uniform_real_distribution<> unif(-3.0, 3.0);
	//ヒストグラム表示
	show_histgram(normal, engine);
	show_histgram(unif, engine);
	//値表示
	show_value(normal, engine, 5);
	show_value(normal, engine, 5);
}

実行結果

======= show histgram =========
-8
-7
-6
-5
-4 *
-3 ***
-2 ******
-1 ********
 0 **********
 1 ********
 2 *****
 3 ***
 4 *
 5
 6
 7
 8
======= show histgram =========
-3 ****
-2 ********
-1 ********
 0 ********
 1 ********
 2 *******
 3 ****
======= show values =========
1.0
4.0
-3.2
-1.3
-5.1
======= show values =========
1.8
1.0
4.0
-3.2
-1.3

Xを越える最初のコンテナの要素へのイテレーターを返す

毎回関数オブジェクト使ってたんだけどlower_boundってのがあるんだなって。
lower_boundは"以上(>=)"なんだけど、"より大きい(>)"をやるには同様にupper_boundってのがあるのか。

#include <iostream>
#include <vector>
#include <algorithm>

int main()
{
	//適当なデータ
	std::vector<double> x = { 1, 3, 5, 7, 8, 9 };
	//プレディケード版
	struct Pred{
		Pred(double x) : x_(x){}
		bool operator()(double x){ return x > x_; }
		double x_;
	};
	std::vector<double>::const_iterator it1 = std::find_if(x.begin(), x.end(), Pred(3.3));
	std::cout << "3.3を越える最初のデータ:" << *it1 << std::endl;
	//lower_bound版
	std::vector<double>::const_iterator it2 = std::lower_bound(x.begin(), x.end(), 3.3);
	std::cout << "3.3を越える最初のデータ:" << *it2 << std::endl;

	return 0;
}
3.3を越える最初のデータ:5
3.3を越える最初のデータ:5

std::greaterとstd::lessの挙動がよくわからん

あるクラスのオブジェクトが入ったコンテナを、そのクラスのメンバーの大小に応じて、ソートしたい、そんな時、あると思います。
だけど、書き方がよくわからんかったのでメモ。クラスの外に比較用のプレディケェード作れば楽ってのは知ってるのだが、こうしたかった。
この辺の「sort比較演算子は < がデフォで > の時にはなんかある」みたいな話はどこかのC++本 or サイトで見た記憶があるのだが全く思い出せない…

そして、以下のコードはVS2013だと通るんだけど、ideonegcc(4.8.1)で試したらアウトだった。ぐぬぬ

#include<iostream>
#include<vector>
#include <functional>
#include<algorithm>
//適当なクラス
struct Hoge
{
	Hoge(int x) : x_(x){}
	bool operator<(const Hoge & inRhs){ return x_ < inRhs.x_; }
	bool operator>(const Hoge & inRhs){ return !(this->operator<(inRhs.x_)); }
	int x_;
};

int main()
{
	//適当なデータ
	std::vector<Hoge> hoges;
	hoges.push_back(Hoge(9));
	hoges.push_back(Hoge(1));
	hoges.push_back(Hoge(3));
	hoges.push_back(Hoge(7));
	hoges.push_back(Hoge(4));
	
	std::cout << "元のデータ" << std::endl;
	std::for_each(hoges.begin(), hoges.end(), [](Hoge & hoge){std::cout << hoge.x_ << std::endl; });

	//↓はだめ
	//std::sort(hoges.begin(), hoges.end(), std::less<Hoge>());
	//↓はいい
	//std::sort(hoges.begin(), hoges.end(), std::less<>());
	//↓はいい
	//std::sort(hoges.begin(), hoges.end(), std::less<Hoge&>());
	std::sort(hoges.begin(), hoges.end());
	std::cout << "x_の昇順にソートしたデータ" << std::endl;
	std::for_each(hoges.begin(), hoges.end(), [](Hoge & hoge){std::cout << hoge.x_ << std::endl; });
	
	//↓はだめ
	//std::sort(hoges.begin(), hoges.end(), std::greater<Hoge>());
	//↓はいい
	//std::sort(hoges.begin(), hoges.end(), std::greater<Hoge&>());
	std::sort(hoges.begin(), hoges.end(), std::greater<>());
	std::cout << "x_の降順にソートしたデータ" << std::endl;
	std::for_each(hoges.begin(), hoges.end(), [](Hoge & hoge){std::cout << hoge.x_ << std::endl; });
	return 0;
}

実行結果。

元のデータ
9
1
3
7
4
x_の昇順にソートしたデータ
1
3
4
7
9
x_の降順にソートしたデータ
9
7
4
3
1

〜2014/01/31追記
コメント欄でアドバイスいただいたように、constメソッドになってないからだった。↓にすれば全部のコードでOKだった。
ありがとうございます!

struct Hoge
{
	Hoge(int x) : x_(x){}
	bool operator<(const Hoge & inRhs) const{ return x_ < inRhs.x_; }  
	bool operator>(const Hoge & inRhs) const{ return !(this->operator<(inRhs.x_)); }
	int x_;
};

ダブル・ディスパッチを書いてみる

意識しないで使ってそうだが、ダブル・ディスパッチ~ 典型的なオブジェクト指向プログラミング・イディオム ~にあるダブル・ディスパチをC++でメモっておく。
これは要するにif-else or switch的な処理で書いてしまいそうな所を、あるメソッド数呼び出しの中で自身を引数として別な関数を呼び出す事で回避するテクニック。

#include<iostream>
//前方宣言
class Member;
class CD;
class DVD;

//Member系
class Member
{
public:
    virtual int calculateRentalFeeForCD(CD & item) = 0;
    virtual int calculateRentalFeeForDVD(DVD & item) = 0;
};
class CommonMember : public Member
{
public:
    int calculateRentalFeeForCD(CD & item){return 100;} 
    int calculateRentalFeeForDVD(DVD & item){return 300;} 
};
class GoldMember : public Member
{
public:
    int calculateRentalFeeForCD(CD & item){return 99;} 
    int calculateRentalFeeForDVD(DVD & item){return 100;} 
};

//Item系
class Item
{
public:
    virtual int calculateRentalFee(Member & member) = 0;
};
class CD : public Item
{
public:
    int calculateRentalFee(Member & member){return member.calculateRentalFeeForCD(*this);}
};
class DVD : public Item
{
public:
    int calculateRentalFee(Member & member){return member.calculateRentalFeeForDVD(*this);}
};

//メイン
int main()
{
    CommonMember common;
    GoldMember gold;
    CD cd;
    DVD dvd;
    std::cout << "Member:Common, Item:CD,  Fee:" << cd.calculateRentalFee(common) << std::endl;
    std::cout << "Member:Gold,   Item:CD,  Fee:" << cd.calculateRentalFee(gold) << std::endl;
    std::cout << "Member:Common, Item:DVD, Fee:" << dvd.calculateRentalFee(common) << std::endl;
    std::cout << "Member:Gold,   Item:DVD, Fee:" << dvd.calculateRentalFee(gold) << std::endl;
    return 0;
}

実行結果

Member:Common, Item:CD,  Fee:100
Member:Gold,   Item:CD,  Fee:99
Member:Common, Item:DVD, Fee:300
Member:Gold,   Item:DVD, Fee:100

Boostのlibファイルのリンクは自動で行われている

Boost C++ Library プログラミングより

unit_test、python以外のビルドが必要であったライブラリ(regex、thread、filesystemなど)は、Boostのヘッダ側で自動リンク設定がなされています。これらは、ヘッダを#includeすると自動でリンクの設定が行われるため、ユーザがリンクするファイル名を指定する必要はありません。将来的には残る二つのライブラリにも自動リンク設定が実装されるものと思われます。

そうだったんだー。今まで「そういや明示的にlibファイル指定した覚えがないな」と思っていたので。

vector中の特定の条件を満たす要素のインデックスだけを抽出

vector中の特定の条件を満たす要素だけを抽出 - My Life as a Mock Quantで要素自身を抜いていたけど、
これが大きいオブジェクトだったらコピーコストが凄い事にと思うと夜も眠れないので、インデックスだけ抜くようにした…ら…ば…結構めんどい書き方になった。
何方かもっといいやり方教えてください。

#include<iostream>
#include<vector>
#include<algorithm>
#include <functional>

int main()
{
    //テストデータ
    std::vector<int> x,y;
    x.push_back(1);
    x.push_back(3);
    x.push_back(4);
    x.push_back(5);
    x.push_back(3);
    //条件用Functor
    struct IsNotThree : public std::unary_function<int, bool>
    {
        bool operator()(int x) const{return x!=3;}
    };
    //インデックス抽出
    std::vector<int>::iterator it = std::find_if(x.begin(), x.end(), IsNotThree());
    while (it != x.end()) {
       y.push_back(std::distance(x.begin(), it));
       it = std::find_if(++it, x.end(), IsNotThree());
    }
    //表示
    struct Show{void operator()(int x){std::cout << x << std::endl;}};
    std::for_each(y.begin(), y.end(), Show());    
    return 0;
}

実行結果

0
2
3