ちょっとした処理を行う関数,クラス(C,C++)



ストリーム出力

テキストファイルへも同時に出力するカスタムストリーム出力

#include <iostream>
#include <fstream>
#include <sstream>

template<typename T>
inline std::string RX_TO_STRING(const T &x)
{
	std::stringstream ss;
	ss << x;
	return ss.str();
}

// カスタムストリーム出力
class rxLog
{
	std::fstream m_ofLog;
public:

	rxLog(const char *filename)
	{
		m_ofLog.open(filename, std::ios::out);
		if(!m_ofLog || !m_ofLog.is_open() || m_ofLog.bad() || m_ofLog.fail()){
			return;
		}
	}
	~rxLog()
	{
		if(m_ofLog && m_ofLog.is_open()) m_ofLog.close();
	}

	//! <<オペレータを設定
	template<typename T>
	rxLog& operator<<(const T &a)
	{
		std::cout << a;
		if(m_ofLog) m_ofLog << RX_TO_STRING(a);
		return *this;
	}

	// std::coutの型
	typedef std::basic_ostream<char, std::char_traits<char> > TypeCout;

	// std::endlのためのオペレータ<<を定義
	// (std::endlはstd::coutを引数としてとる関数)
	rxLog& operator<<(TypeCout& (*manip)(TypeCout&))
	{
		manip(std::cout);
		if(m_ofLog) m_ofLog << std::endl;
		return *this;
	}
};

static rxLog RXCOUT("test.log");

数値や文字列の出力だけならば<<オペレータのオーバーロードだけでよいが, endlにも対応させるために追加の<<オペレータを定義している.

使用例:

RXCOUT << "x = " << x << std::endl;

ヘルプテキスト表示サンプル

//! ヘルプテキストを表示
void help(void)
{
    static const char* help = "[help]\n"
		" ESC : quit the program\n"
        " 's' : toggle animation on/off\n"
        " Shift+'f' : toggle fullscreen mode\n"
        " 'h' : show this help";
    std::cout << help << std::endl;
}

テキストストリーム

テキストファイルストリームを開く

/*!
 * ファイルストリームを開く
 * @param[out] file ファイルストリーム
 * @param[in] path  ファイルパス
 * @param[in] rw    入出力フラグ (1:読込専用, 2:書込専用, 4:読み書き)
 * @return ファイルオープン成功:1, 失敗:0
 */
static inline int OpenFileStream(fstream &file, const string &path, int rw = 1)
{
	file.open(path.c_str(), (rw & 0x01 ? ios::in : 0)|(rw & 0x02 ? ios::out : 0));
	if(!file || !file.is_open() || file.bad() || file.fail()){
		return 0;
	}
	return 1;
}

テキストファイルから文字列リストを読み込む

空行やコメント行を除いて,各行を文字列として配列に格納する.

/*!
 * テキストファイルストリームから文字列リストを読み込む
 *  - コメント(%,#,//),空行は無視する
 * @param[in] file ファイルストリーム
 * @param[out] lines 各行の文字列を格納した配列
 * @return 読み込んだ行数
 */
static inline int ReadTextStream(fstream &file, vector<string> &lines)
{
	int k = 0;
	string buf;
	string::size_type comment_start = 0;
	while(!file.eof()){
		getline(file, buf);

		// '%'以降はコメントとして無視
		if( (comment_start = buf.find('%')) != string::size_type(-1) ){
			buf = buf.substr(0, comment_start);
		}

		// '//'以降はコメントとして無視
		if( (comment_start = buf.find("//")) != string::size_type(-1) ){
			buf = buf.substr(0, comment_start);
		}

		// '#'以降はコメントとして無視
		if( (comment_start = buf.find("#")) != string::size_type(-1) ){
			buf = buf.substr(0, comment_start);
		}

		// 行頭のスペース,タブを削除
		size_t stpos;
		while((stpos = buf.find_first_of("  \t")) == 0){
			buf.erase(buf.begin());
			if(buf.empty()) break;
		}

		// 空行は無視
		if(buf.empty()){
			continue;
		}

		lines.push_back(buf);
		k++;
	}

	return k;
}

/*!
 * テキストファイルから文字列リストを読み込む
 *  - コメント(%,#,//),空行は無視する
 * @param[in] file ファイルパス
 * @param[out] path 各行の文字列を格納した配列
 * @return 読み込んだ行数
 */
static inline int ReadTextStream(const string path, vector<string> &lines)
{
	fstream file;
	file.open(path.c_str(), ios::in);
	if(!file || !file.is_open() || file.bad() || file.fail()){
		return 0;
	}
	int nlines = ReadTextStream(file, lines);
	file.close();
	return nlines;
}

ビット演算

2進数文字列の生成

/*!
 * 整数を2進数文字列に変換
 * @param[in] x 元の整数
 * @param[in] bit 2進数桁数
 * @return 2進数文字列
 */
string GetBitArray(int x, int bit)
{
	string s;
	s.resize(bit, '0');
	for(int i = 0; i < bit; ++i){
		s[bit-i-1] = ((x >> i) & 0x01) ? '1' : '0';
	}
	return s;
}

ビット演算によるフラグ管理

enum
{
	RX_BIT_A = 0x0001, 
	RX_BIT_B = 0x0002, 
	RX_BIT_C = 0x0004, 
	RX_BIT_D = 0x0008, 
	RX_BIT_E = 0x0010, 

	RX_ALL = 0xffff,
};

int main(void)
{
	int flag = 0;					// 00000

	// フラグON
	flag |= RX_BIT_B;				// 00010
	flag |= (RX_BIT_A | RX_BIT_D);	// 01011

	// フラグOFF
	flag &= ~RX_BIT_B;				// 01001
	flag &= ~(RX_BIT_A | RX_BIT_D);	// 00000

	// フラグ反転
	flag ^= RX_BIT_E;				// 10000

	// 全フラグ反転
	flag ^= RX_ALL;					// 01111

	// 要素参照
	if(flag & RX_BIT_A) cout << "A";
	if(flag & RX_BIT_B) cout << "B";
	if(flag & RX_BIT_C) cout << "C";
	if(flag & RX_BIT_D) cout << "D";
	if(flag & RX_BIT_E) cout << "E";
	cout << endl;					// ABCD

	return 0;
}

画面出力

可変引数リストを用いたカスタム版printf

#include <stdarg.h>

struct Vec2
{
	double data[2];
	double& operator[](int i){ return data[i]; }
};

struct Vec3
{
	double data[3];
	double& operator[](int i){ return data[i]; }
};

/*!
 * 可変引数リスト"..."を使ったテキストファイル出力
 * @param[in] fn 出力ファイル名
 * @param[in] mode ファイルオープンモード("w" or "a")
 * @param[in] fmt 出力フォーマット
 * @param[in] ... 可変引数リスト(フォーマットにより数が異なる)
 */
bool FPrintf(const string fn, const string mode, char *fmt, ...)
{
	FILE* fp;
	if((fp = fopen(fn.c_str(), mode.c_str())) == NULL){
        return 0;
    }

	va_list ap;		// 各引数を順々に参照する変数
	char *p, *sval;
	int ival;
	double dval;
	Vec2 v2val;
	Vec3 v3val;

	va_start(ap, fmt);	// apを最初の引数を指すようにする
	for(p = fmt; *p; ++p){
		if(*p != '%'){
			putc(*p, fp);
			continue;
		}
		switch(*(++p)){
		case 'd':
			ival = va_arg(ap, int);
			fprintf(fp, "%d", ival);
			break;
		case 'f':
			dval = va_arg(ap, double);
			fprintf(fp, "%f", dval);
			break;
		case 's':
			for(sval = va_arg(ap, char*); *sval; ++sval)
				putc(*sval, fp);
			break;
		case 'v':
			switch(*(++p)){
			case '2':
				v2val = va_arg(ap, Vec2);
				fprintf(fp, "(%f, %f)", v2val[0], v2val[1]);
				break;
			case '3':
				v3val = va_arg(ap, Vec3);
				fprintf(fp, "(%f, %f, %f)", v3val[0], v3val[1], v3val[2]);
				break;
			default:
				v3val = va_arg(ap, Vec3);
				fprintf(fp, "(%f, %f, %f)", v3val[0], v3val[1], v3val[2]);
				break;
			}
			break;
		default:
			putc(*p, fp);
			break;
		}
	}
	va_end(ap);

	//char *n = "\n";
	//putc(*n, fp);

	fclose(fp);
	return true;
}

例えば,

int i = 123;
	double x = 4.56;
	Vec2 v2;
	v2[0] = 7.8; v2[1] = 9.0;
	Vec3 v3;
	v3[0] = 1.0; v3[1] = 2.0; v3[2] = 3.0;
	Printf("test.txt", "w", "%s : %d, %f\n", "val", i, x);
	Printf("test.txt", "a", "vec : %v2, %v3\n", v2, v3);

のようなコードを実行すると,test.txtが作られて,

val : 123, 4.560000
vec : (7.800000, 9.000000), (1.000000, 2.000000, 3.000000)

が書き込まれる.

コマンドプロンプトに表示すると共にログファイルにも保存(要boost)

#include <boost/iostreams/stream.hpp>
#include <boost/algorithm/string.hpp>

//! テキストストリーム - コマンドプロンプトに表示すると共にログファイルにも保存
class rxCout : public boost::iostreams::sink
{
	string m_strLog;

public:
	rxCout(string fn)
	{
		m_strLog = fn;
	}

	std::streamsize write(const char* s, std::streamsize n)
	{
		string str;;
		str.resize(n);
		for(int i = 0; i < n; ++i){
			str[i] = s[i];
		}

		cout << str;

		boost::algorithm::replace_all(str, "\n", "");

		static std::ofstream fout(m_strLog, std::ios::out);
		fout << str << endl;
		return n;
	}
};

使うときは,

static boost::iostreams::stream<rxCout> RXCOUT("_log.txt");

などとして,

RXCOUT << "test" << endl;

として用いる.

vector関連

//! vector型に<<オペレータを設定
template<typename T>
inline std::ostream &operator<<(std::ostream &out, const vector<T> &x)
{
	for(size_t i = 0; i < x.size(); ++i){
		out << x[i] << (i == x.size()-1 ? "" : ", ");
	}
	return out;
}

/*!
 * vectorのidx番目の要素を削除(0スタート)
 * @param[in] src vectorコンテナ
 * @param[in] idx 削除要素インデックス
 * @return 削除の可否
 */
template<class T> 
inline void EraseSTLVectori(vector<T> &src, int idx)
{
	src.erase(src.begin()+idx);
}

/*!
 * vectorの特定の要素を削除
 * @param[in] src vectorコンテナ
 * @param[in] comp_func 削除条件関数
 * @return 削除の可否
 */
template<class T> 
inline int EraseSTLVector(vector<T> &src, boost::function<bool (T)> comp_func)
{
	int cnt = 0;
	vector<T>::iterator itr = src.begin();
	while(itr != src.end()){
		if(comp_func(*itr)){
			itr = src.erase(itr);
			cnt++;
		}
		else{
			++itr;
		}
	}

	return cnt;
}

配列

ランダムシャッフル

STLのalgorithmのrandom_shuffle (algorithm#zf86514c参照)の存在に気づく前に作ったもの.

/*!
 * ランダムソート
 * @param[inout] arr 配列
 * @param[in] n 配列の大きさ
 */
template<typename T>
inline void RandomSort(T arr[], int n)
{
	int rnd;
	T temp;

	srand(time(NULL));

	for(int i = 0; i < n; ++i){
		rnd = rand()%n;
		temp = arr[i];
		arr[i] = arr[rnd];
		arr[rnd] = temp;
	}
}

/*!
 * ランダムソート
 * @param[inout] arr 配列
 * @param[in] n 配列の大きさ
 */
template<typename T>
inline void RandomSortV(vector<T> &arr)
{
	int n = (int)arr.size();
	int rnd;
	T temp;

	srand(time(NULL));

	for(int i = 0; i < n; ++i){
		rnd = rand()%n;
		temp = arr[i];
		arr[i] = arr[rnd];
		arr[rnd] = temp;
	}
}

ファイル処理

フォルダ生成

処理系に依存して使えない場合あり.

#include <direct.h>

/*!
 * ディレクトリ作成(多階層対応)
 * @param[in] dir 作成ディレクトリパス
 * @return 成功で1,失敗で0 (ディレクトリがすでにある場合も1を返す)
 */
static int MkDir(string dir)
{
	if(_mkdir(dir.c_str()) != 0){
		char cur_dir[512];
		_getcwd(cur_dir, 512);	// カレントフォルダを確保しておく
		if(_chdir(dir.c_str()) == 0){	// chdirでフォルダ存在チェック
			cout << "MkDir : " << dir << " is already exist." << endl;
			_chdir(cur_dir);	// カレントフォルダを元に戻す
			return 1;
		}
		else{
			size_t pos = dir.find_last_of("\\/");
			if(pos != string::npos){	// 多階層の可能性有り
				int parent = MkDir(dir.substr(0, pos+1));	// 親ディレクトリを再帰的に作成
				if(parent){
					if(_mkdir(dir.c_str()) == 0){
						return 1;
					}
					else{
						return 0;
					}
				}
			}
			else{
				return 0;
			}
		}
	}

	return 1;
}

ファイル名生成

/*!
 * 拡張子を変更したファイル名を生成
 * @param[in] fn 元ファイル名
 * @param[in] ext 変更後の拡張子名
 * @return 拡張子を変更したファイル名
 */
inline string GetFileNameWithExt(const string &fn, const string &ext)
{
	string new_fn = fn;

	size_t pos1 = fn.rfind('.');
	if(pos1 != string::npos){
		new_fn = fn.substr(0, pos1);
	}

	return new_fn+"."+ext;
}

/*!
 * ファイル名生成
 * @param head : 基本ファイル名
 * @param ext  : 拡張子
 * @param n    : 連番
 * @param d    : 連番桁数
 * @return 生成したファイル名
 */
inline string CreateFileName(const string &head, const string &ext, int n, const int &d)
{
	string file_name = head;
	int dn = d-1;
	if(n > 0){
		dn = (int)(log10((double)n))+1;
	}
	else if(n == 0){
		dn = 1;
	}
	else{
		n = 0;
		dn = 1;
	}

	for(int i = 0; i < d-dn; ++i){
		file_name += "0";
	}

	file_name += boost::lexical_cast<std::string>(n);
	file_name += ".";
	file_name += ext;

	return file_name;
}

ファイル探索

boost::filesystem使用版

#include <boost/function.hpp>

#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/fstream.hpp>
 
/*!
 * 再帰的に全ファイルを取り出す
 * @param[in] fpath フォルダパス
 * @param[out] paths 見つかったファイル一覧
 */
static void SearchFiles(const boost::filesystem::path &dpath, vector<string> &paths)
{
	// カレントディレクトリのファイル一覧
	boost::filesystem::directory_iterator end; 
	for(boost::filesystem::directory_iterator it(dpath); it!=end; ++it){
		if(boost::filesystem::is_directory(*it)){
			SearchFiles(it->path(), paths);
		}
		else{
			paths.push_back(it->path().file_string());
		}
	} 
}
 
/*!
 * 再帰的に全ファイルを取り出す
 * @param[in] fpath フォルダパス
 * @param[out] paths 見つかったファイル一覧
 * @param[in] fpComp 検索条件
 */
static void SearchFiles(const boost::filesystem::path &dpath, vector<string> &paths, boost::function<bool (string)> fpComp)
{
	// カレントディレクトリのファイル一覧
	boost::filesystem::directory_iterator end; 
	for(boost::filesystem::directory_iterator it(dpath); it!=end; ++it){
		if(boost::filesystem::is_directory(*it)){
			SearchFiles(it->path(), paths);
		}
		else{
			string fpath = it->path().file_string();
			if(fpComp(fpath)){
				paths.push_back(fpath);
			}
		}
	}
}
 
 
/*!
 * 指定したディレクトリ以下に指定したファイルがあるかどうかを検索
 *  (サブディレクトリ以下も検索)
 * @param[in] dpath ディレクトリパス
 * @param[in] fname 検索ファイル名
 * @param[out] found_path 見つかったパス
 * @return 
 */
static bool FindFile(const boost::filesystem::path &dpath, const std::string &fname, boost::filesystem::path &found_path)
{
	if(!boost::filesystem::exists(dpath)) return false;
 
	boost::filesystem::directory_iterator end_itr;
	for(boost::filesystem::directory_iterator itr(dpath); itr != end_itr; ++itr){
		if(boost::filesystem::is_directory(itr->status())){
			if(FindFile(itr->path(), fname, found_path)) return true;
		}
		else if(itr->leaf() == fname){
			found_path = itr->path();
			return true;
		}
	}
	return false;
}

/*!
 * ファイル名比較関数(拡張子)
 * @param[in] fn 比較したいファイル名
 * @param[in] ext 拡張子
 * @return fnの拡張子がextと同じならtrue
 */
inline bool SearchCompExt(const string &fn, const string &ext)
{
	return (fn.find(ext, 0) != string::npos);
}

Windows API使用版.RX_S2W,RX_W2Sはプロジェクトの設定でUnicode文字セットを使用している場合のみ必要. マルチバイト文字セットにしている場合は必要なし.

#include <cstdlib>
#include <windows.h>
#include <tchar.h>

#include <shlwapi.h>
#pragma comment(lib, "shlwapi.lib")

/*!
 * ワイド文字列(wstring)からマルチバイト文字列(string)へ変換
 *  - 用いる前に setlocale(LC_CTYPE, ""); としておくこと
 * @param[in] src ワイド文字列(wstring)
 * @return マルチバイト文字列(string)
 */
inline static std::string RX_W2S(const std::wstring &src)
{
	char *mbs = new char[src.length() * MB_CUR_MAX + 1];
	wcstombs(mbs, src.c_str(), src.length() * MB_CUR_MAX + 1);
	std::string dst = mbs;
	delete [] mbs;
	return dst;
}

/*!
 * マルチバイト文字列(string)からワイド文字列(wstring)へ変換
 *  - 用いる前に setlocale(LC_CTYPE, ""); としておくこと
 * @param[in] src マルチバイト文字列(string)
 * @return ワイド文字列(wstring)
 */
inline static std::wstring RX_S2W(const std::string &src)
{
	wchar_t *wcs = new wchar_t[src.length() + 1];
	mbstowcs(wcs, src.c_str(), src.length() + 1);
	std::wstring dst = wcs;
	delete [] wcs;
	return dst;
}


/*!
 * 再帰的に全ファイル(拡張子指定)を取り出す
 * @param[in] dpath フォルダパス
 * @param[out] paths 見つかったファイル一覧
 * @param[inout] d 現在の階層数
 * @param[in] n 最大階層数
 * @param[in] exts 拡張子指定
 */
static void SearchFiles(const std::string &dpath, std::vector<std::string> &paths, int d, const int n, 
						const std::vector<std::string> &exts)
{
	HANDLE handle;
	WIN32_FIND_DATA fd;

	// search first file with the wildcard "*" to find the all type of file
	handle = FindFirstFile(RX_S2W(dpath+"\\*").c_str(), &fd);

	// if fail to find the file
	if(handle == INVALID_HANDLE_VALUE){
		return;
	}

	// search next files
	do{
		// file name
		std::string name = RX_W2S(static_cast<LPCTSTR>(fd.cFileName));
		std::string fpath = dpath+"\\"+name;

		if(name == "." || name == "..") continue;

		if((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && (n == -1 || d < n)){
			// if the path is directory, recursively search in the directory
			SearchFiles(fpath, paths, d+1, n, exts);
		}
		else{
			vector<std::string>::const_iterator i;
			for(i = exts.begin(); i != exts.end(); ++i){
				if(fpath.find(*i, 0) != std::string::npos) break;
			}
			
			// store the file path if the extension was matched
			if(i != exts.end()){
				paths.push_back(fpath);
			}
		}
	}while(FindNextFile(handle, &fd));

	// terminate the search
	FindClose(handle);
}

static void SearchFiles(const std::string &dir, std::vector<std::string> &paths, 
						std::vector<std::string> exts, const int n = 0)
{
	if(PathIsDirectory(RX_S2W(dir).c_str())){	// dirがディレクトリであるかどうかのチェック
		int d = 0;
		SearchFiles(dir, paths, d, n, exts);
	}
}

ファイルの存在確認

boost::filesystemを用いた場合,

/*!
 * ファイル,フォルダの存在確認
 * @param[in] path_str ファイル・フォルダパス
 */
bool ExistFile(const string &path_str)
{
	fspath fnph(path_str);
	return boost::filesystem::exists(fnph);
}

fopenを用いる場合,

int FileExist(const char *fn)
{
    FILE *fp;

	if( (fp = fopen(fn, "r")) == NULL ){
        return 0;
	}

    fclose(fp);
    return 1;
}

fstreamでバイナリファイルの読み書き

#include <iostream>
#include <fstream>
#include <sstream>

#include <cstdlib>

using namespace std;

int main(void)
{
	srand(12345);

	// ランダムなデータ
	const int N = 10;
	double a[N];
	for(int i = 0; i < N; ++i) a[i] = rand()/(double)RAND_MAX;

	// バイナリファイルの書き込み
	ofstream fout;
	fout.open("binary_test.dat", ios::out|ios::binary);	// ファイルをバイナリモードで開く
	if(!fout){
		cout << "file couldn't open." << endl;
		return 1;
	}

	for(int i = 0; i < N; ++i){
		//fout << a[i];
		fout.write((char*)&a[i], sizeof(double));
		cout << a[i] << ", ";	// 確認用
	}
	cout << endl;

	fout.close();

	// バイナリファイルの読み込み
	ifstream fin;
	fin.open("binary_test.dat", ios::in|ios::binary);	// ファイルをバイナリモードで開く
	if(!fin){
		cout << "file couldn't find." << endl;
		return 1;
	}

	double x;
	for(int i = 0; i < N; ++i){
		//fin >> x;
		fin.read((char*)&x, sizeof(double));
		cout << x << ", ";	// 確認用
	}
	cout << endl;

	fin.close();

	// ファイルの一分部のみ読み取り
	fin.open("binary_test.dat", ios::in|ios::binary);	// ファイルをバイナリモードで開く
	if(!fin){
		cout << "file couldn't find." << endl;
		return 1;
	}

	int j = 3;
	fin.seekg(j*sizeof(double));	// 読み込み場所の移動
	fin.read((char*)&x, sizeof(double));
	cout << j << " : " << x << endl;

	fin.close();
}

数字処理

数字の桁数を数える

/*!
 * 数字の桁数をカウント
 * @param[in] n 数字
 * @return 桁数
 */
inline int CountDigit(int n)
{
	int d = 0;
	if(n > 0){
		return (int)(log10((double)n))+1;
	}
	else if(n == 0){
		return 1;
	}
	else{
		return (int)(log10((double)(-n)))+1;
	}
}

整数値の下一桁の値を抽出

/*!
 * 整数値の下一桁を返す
 * @param[in] x 整数値
 * @return xの下一桁
 */
inline int ExtractLastDigit(const int &x)
{
    int x1 = (x < 0) ? -x : x;
    return x1-(int)(x1/10)*10;
}

整数値の任意桁の値を抽出

/*!
 * 整数値の任意の桁の値を抽出して返す
 * @param[in] x 整数値
 * @param[in] d 桁(1<=d<=xの桁数,それ以外では0を返す)
 * @return 任意の桁の値
 */
inline int ExtractAnyDigit(const int &x, const int &d)
{
	if(d <= 0) return 0;

    int x1 = (x < 0) ? -x : x;
	int c = (int)log((double)x1);	// xの桁数
	if(d > c) return 0;

	int a = (int)pow(10.0, (double)d);	// 10^d
    return (x1-(int)(x1/a)*a)/(a/10);
}

0付き数字の生成

/*!
 * 0付きの数字を生成
 * @param[in] n 数字
 * @param[in] d 桁数
 * @return 0付きの数字(string)
 */
inline string GenZeroNo(int n, const int &d)
{
	string zero_no = "";
	int dn = d-1;
	if(n > 0){
		dn = (int)(log10((double)n))+1;
	}
	else if(n == 0){
		dn = 1;
	}
	else{
		n = 0;
		dn = 1;
	}

	for(int i = 0; i < d-dn; ++i){
		zero_no += "0";
	}

	zero_no += boost::lexical_cast<std::string>(n);

	return zero_no;
}

時間計測

ストップウォッチクラス

//-----------------------------------------------------------------------------
// インクルードファイル
//-----------------------------------------------------------------------------
#include <iostream>

#include <vector>
#include <string>

#define RX_USE_MM
#ifdef WIN32
    #include <windows.h>
 
    #ifdef RX_USE_MM
    #include <mmsystem.h>
    #pragma comment (lib, "winmm.lib")
    #endif
 #endif
 
#ifdef WIN32
    #ifdef RX_USE_MM
        #define RXTIME DWORD
        #define RXGETTIME timeGetTime
        #define RXTIME2SEC 1.0e-3
        //#define RXTIME2SEC 1.0
    #else
        #define RXTIME DWORD
        #define RXGETTIME GetTickCount
        #define RXTIME2SEC 1.0e-3
        //#define RXTIME2SEC 1.0
    #endif
#else
    #define RXTIME clock_t
    #define RXGETTIME clock
    #define RXTIME2SEC (1.0/CLOCKS_PER_SEC)
#endif
 

using namespace std;



//-----------------------------------------------------------------------------
// 時間計測クラス
//-----------------------------------------------------------------------------
class rxTimer
{
    RXTIME m_tStart, m_tEnd;
    vector<double> m_vTimes;
    vector<string> m_vComments;
 
public:
    //! コンストラクタ
    rxTimer(){}
 
    //! デストラクタ
    ~rxTimer(){}
 
    //! 計測開始
    void Start(void)
    {
        m_tStart = RXGETTIME();
    }
 
    //! 計測
    void Split(const string &cmnt = "", bool restart = false)
    {
        m_tEnd = RXGETTIME();
 
        double time = (double)(m_tEnd-m_tStart)*RXTIME2SEC;
        m_vTimes.push_back(time);
        m_vComments.push_back(cmnt);
 
        if(restart) m_tStart = RXGETTIME();
    }
 
    //! 計測終了
    void Stop(const string &cmnt = "")
    {
        m_tEnd = RXGETTIME();
 
        double time = (double)(m_tEnd-m_tStart)*RXTIME2SEC;
        m_vTimes.push_back(time);
        m_vComments.push_back(cmnt);
 
        m_tStart = m_tEnd = 0;
    }
 
    //! リセット
    void Reset(void)
    {
        m_vTimes.clear();
        m_vComments.clear();
        m_tStart = m_tEnd = 0;
    }
 
    // 最後に記録された時間を削除
    void PopBackTime(void)
    {
        m_vTimes.pop_back();
        m_vComments.pop_back();
    }
 
    //! 時間をセット(他の計測方法で計測した結果など)
    void SetTime(const double &t, const string &cmnt = "")
    {
        m_vTimes.push_back(t);
        m_vComments.push_back(cmnt);
    }
 
    //! 時間の取得
    double GetTime(int i)
    {
        if(i >= (int)m_vTimes.size()) return 0.0;
 
        return m_vTimes[i];
    }
 
    //! 記録された時間数の取得
    int GetTimeNum(void)
    {
        return (int)m_vTimes.size();
    }
 
    //! 記録された時間を画面出力
    double Print(void)
    {
        int m = 0, mi;
        if(m_vTimes.empty()){
            return 0.0;
        }
        else{
            // 総計測時間を計算
            double total = 0.0;
            for(int i = 0; i < (int)m_vTimes.size(); ++i){
                mi = (int)m_vComments[i].size();
                if(mi > m) m = mi;
 
                total += m_vTimes[i];
            }
 
            SetTime(total, "total");
        }
 
        int cur_p = cout.precision();
        cout.precision(3);
        cout.setf(ios::fixed);
        for(int i = 0; i < (int)m_vTimes.size(); ++i){
            string spc;
			for(int k = 0; k < m-(int)m_vComments[i].size(); ++k) spc += " ";
            cout << m_vComments[i] << spc << " : " << m_vTimes[i] << endl;
        }
        cout.unsetf(ios::fixed);
        cout.precision(cur_p);
 
        double t = m_vTimes.back();
 
        PopBackTime(); // 格納した合計時間を次の計算に備えて削除
 
        return t;
    }
 
    //! 記録された時間を文字列に出力
    double PrintToString(string &str)
    {
        int m = 0, mi;
        if(m_vTimes.empty()){
            return 0.0;
        }
        else{
            // 総計測時間を計算
            double total = 0.0;
            for(int i = 0; i < (int)m_vTimes.size(); ++i){
                mi = (int)m_vComments[i].size();
                if(mi > m) m = mi;
 
                total += m_vTimes[i];
            }
 
            SetTime(total, "total");
        }
 
        stringstream ss;
        ss.precision(3);
        ss.setf(ios::fixed);
        
        int n = (int)m_vTimes.size();
        for(int i = 0; i < n; ++i){
			string spc;
			for(int k = 0; k < m-(int)m_vComments[i].size(); ++k) spc += " ";
            ss << m_vComments[i] << spc << " : " << m_vTimes[i] << "\n";
        }
 
        ss << "\n";
        str = ss.str();
 
        double t = m_vTimes.back();
 
        PopBackTime(); // 格納した合計時間を次の計算に備えて削除
 
        return t;
    }
};

平均値の計測

class rxTimerAvg
{
public:
	// 時間と計測回数
	struct rxTimeAndCount
	{
		double time;
		int count;
		int idx;
	};

	// 時間と計測回数を文字列と関連づけるマップ
	typedef map<string, rxTimeAndCount> RXMAPTC;

private:
	rxTimer m_Tmr;		//!< 時間計測クラス
	RXMAPTC m_TimeMap;	//!< 時間と計測回数を文字列と関連づけるマップ

public:
    //! コンストラクタ
	rxTimerAvg()
	{
		Clear();
		ResetTime();
		ClearTime();
	}

	/*!
	 * すべてクリア
	 */
	void Clear(void)
	{
		m_TimeMap.clear();
	}

	/*!
	 * 蓄積時間の初期化
	 */
	void ClearTime(void)
	{
		for(RXMAPTC::iterator it = m_TimeMap.begin(); it != m_TimeMap.end(); ++it){
			it->second.time = 0.0;
			it->second.count = 0;
			//it->second.idx = -1;
		}
	}

	/*!
	 * リセット
	 */
	void ResetTime(void)
	{
		m_Tmr.Reset();
		m_Tmr.Start();
	}

	/*!
	 * 計測
	 * @param[in] cmnt 時間蓄積用の名前
	 */
	void Split(const string &cmnt)
	{
		RXMAPTC::iterator i = m_TimeMap.find(cmnt);
		
		m_Tmr.Stop();
		if(i == m_TimeMap.end()){
			
			m_TimeMap[cmnt].time = m_Tmr.GetTime(0);
			m_TimeMap[cmnt].count = 1;
			m_TimeMap[cmnt].idx = m_TimeMap.size()-1;
		}
		else{
			m_TimeMap[cmnt].time += m_Tmr.GetTime(0);
			m_TimeMap[cmnt].count++;
		}
		m_Tmr.Reset();
		m_Tmr.Start();
	}

	/*!
	 * 総時間の取得
	 * @return 総時間
	 */
	double GetTotalTime(void)
	{
		if(m_TimeMap.empty()){
			m_Tmr.Stop();
			return m_Tmr.GetTime(0);
		}
		else{
			double total = 0.0;
			for(RXMAPTC::iterator it = m_TimeMap.begin(); it != m_TimeMap.end(); ++it){
				total += it->second.time/it->second.count;
			}

			return total;
		}
	}

	/*!
	 * 記録された時間を画面出力
	 */
	void Print(void)
	{
		int m = 0, mi;
		double total = 0.0;
		for(RXMAPTC::iterator it = m_TimeMap.begin(); it != m_TimeMap.end(); ++it){
			mi = (int)it->first.size();
			if(mi > m) m = mi;

			total += it->second.time/it->second.count;
		}

        int cur_p = cout.precision();
        cout.precision(3);
        cout.setf(ios::fixed);
		for(RXMAPTC::iterator it = m_TimeMap.begin(); it != m_TimeMap.end(); ++it){
			string spc = RXFunc::GenSpace( m-(int)(it->first.size()) );

			RXCOUT << it->first << spc << " : " << (it->second.time/it->second.count) << "[s]" << endl;
		}
        cout.unsetf(ios::fixed);
        cout.precision(cur_p);

		string spc = RXFunc::GenSpace(m-5);
		RXCOUT << "total" << spc << " : " << total << endl;
	}

	/*!
	 * 記録された時間を文字列に出力
	 * @param[out] str 出力文字列
	 */
	void PrintToString(string &str)
	{
		int m = 0, mi;
		double total = 0.0;
		for(RXMAPTC::iterator it = m_TimeMap.begin(); it != m_TimeMap.end(); ++it){
			mi = (int)it->first.size();
			if(mi > m) m = mi;

			total += it->second.time/it->second.count;
		}

		stringstream ss;
		ss.precision(3);
		ss.setf(ios::fixed);
		for(int i = 0; i < (int)m_TimeMap.size(); ++i){
			RXMAPTC::iterator it = m_TimeMap.begin();

			for(it = m_TimeMap.begin(); it != m_TimeMap.end(); ++it){
				if(it->second.idx == i){
					break;
				}
			}

			string spc = RXFunc::GenSpace(m-(int)(it->first.size()));
			ss << it->first << spc << " : " << (it->second.time/it->second.count) << "[s]\n";
		}

		string spc = RXFunc::GenSpace(m-5);
		ss << "total" << spc << " : " << total << "[s]\n";

		str = ss.str();
	}
};

現在時刻の取得

#include <iostream>
#include <string>
#include <ctime>

const std::string WEEK[7] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };

int main(void)
{
	time_t timer;
	tm *time_st;

	// 現在時刻の取得
	time(&timer);

	// 文字列で表示
	cout << "現在時刻 : " << ctime(&timer) << endl;

	// 構造体に変換
	time_st = localtime(&timer);
	// 日付(年は西暦年-1900,月は1月=0)
	cout << "日付 : " << time_st->tm_year+1900 << "/" << time_st->tm_mon+1 << "/" << time_st->tm_mday << endl;
	// 時刻
	cout << "時刻 : " << time_st->tm_hour << ":" << time_st->tm_min << ":" << time_st->tm_sec << endl;
	// 曜日(日曜日=0)
	cout << "曜日 : " << WEEK[time_st->tm_wday] << endl;
	// 年間日
	cout << "年間日 : " << time_st->tm_yday << endl;
	// サマータイムラグ
	cout << "サマータイムラグ : " << time_st->tm_isdst << endl;

	return 0;
}

実行結果の例

現在時刻 : Wed Aug 31 13:11:31 2011

日付 : 2011/8/31
時刻 : 13:11:31
曜日 : Wednesday
年間日 : 242
サマータイムラグ : 0

行列

行列とベクトルの積

/*!
 * 4x4行列と4次元ベクトルのかけ算(d = m x v)
 * @param[out] d 結果のベクトル
 * @param[in] m 4x4行列
 * @param[in] v 4次元ベクトル
 */
template<class T> 
inline void MulMatVec4(T d[4], const T m[4][4], const T v[4])
{
	d[0] = (v[0]*m[0][0]+v[1]*m[0][1]+v[2]*m[0][2]+v[3]*m[0][3]);
	d[1] = (v[0]*m[1][0]+v[1]*m[1][1]+v[2]*m[1][2]+v[3]*m[1][3]);
	d[2] = (v[0]*m[2][0]+v[1]*m[2][1]+v[2]*m[2][2]+v[3]*m[2][3]);
	d[3] = (v[0]*m[3][0]+v[1]*m[3][1]+v[2]*m[3][2]+v[3]*m[3][3]);
}

/*!
 * 4次元ベクトルと4x4行列のかけ算(d = v x m)
 * @param[out] d 結果のベクトル
 * @param[in] v 4次元ベクトル
 * @param[in] m 4x4行列
 */
template<class T> 
inline void MulVecMat4(T d[4], const T v[4], const T m[4][4])
{
	d[0] = (v[0]*m[0][0]+v[1]*m[1][0]+v[2]*m[2][0]+v[3]*m[3][0]);
	d[1] = (v[0]*m[0][1]+v[1]*m[1][1]+v[2]*m[2][1]+v[3]*m[3][1]);
	d[2] = (v[0]*m[0][2]+v[1]*m[1][2]+v[2]*m[2][2]+v[3]*m[3][2]);
	d[3] = (v[0]*m[0][3]+v[1]*m[1][3]+v[2]*m[2][3]+v[3]*m[3][3]);
}

/*!
 * nxn行列とn次元ベクトルのかけ算(d = m x v)
 * @param[out] d 結果のベクトル
 * @param[in] m nxn行列(2次元配列)
 * @param[in] v n次元ベクトル
 * @param[in] n ベクトル,行列のサイズ
 */
template<class T> 
inline void MulMatVec(T *d, T **m, T *v, int n)
{
	for(int i = 0; i < n; ++i){
		d[i] = (T)0;
		for(int j = 0; j < n; ++j){
			d[i] += v[j]*m[i][j];
		}
	}
}

/*!
 * nxn行列とn次元ベクトルのかけ算(d = v x m)
 * @param[out] d 結果のベクトル
 * @param[in] v n次元ベクトル
 * @param[in] m nxn行列(2次元配列)
 * @param[in] n ベクトル,行列のサイズ
 */
template<class T> 
inline void MulVecMat(T *d, T *v, T **m, int n)
{
	for(int i = 0; i < n; ++i){
		d[i] = (T)0;
		for(int j = 0; j < n; ++j){
			d[i] += v[j]*m[j][i];
		}
	}
}

行列の画面出力

/*!
 * 行列の画面出力
 * @param[in] header 出力の文字列部分
 * @param[in] matrix 行列を格納した配列
 * @param[in] nx,ny  行列の大きさ
 * @return 
 */
static void PrintMatrix(string header, double *matrix, int nx, int ny)
{
	int n = (int)header.size();

	string disp = "%f ";
	for(int j = 0; j < ny; ++j){
		if(j == 0){
			printf("%s", header.c_str());
		}
		else{
			for(int k = 0; k < n; ++k) printf(" ");
		}
		printf("| ");
		for (int i = 0; i < nx; ++i){
			printf(disp.c_str(), matrix[j*nx+i]); 
		}
		printf(" |\n");
	}
//	printf("\n");
}

/*!
 * 行列のファイル出力
 * @param[in] fp ファイルポインタ
 * @param[in] header 出力の文字列部分
 * @param[in] matrix 行列を格納した配列
 * @param[in] nx,ny  行列の大きさ
 * @return 
 */
static void FPrintMatrix(FILE *fp, string header, double *matrix, int nx, int ny)
{
	int n = (int)header.size();

	string disp = "%f ";
	for(int j = 0; j < ny; ++j){
		if(j == 0){
			fprintf(fp, "%s", header.c_str());
		}
		else{
			for(int k = 0; k < n; ++k) fprintf(fp, " ");
		}
		fprintf(fp, "| ");
		for (int i = 0; i < nx; ++i){
			fprintf(fp, disp.c_str(), matrix[j*nx+i]); 
		}
		fprintf(fp, " |\n");
	}
}


/*!
 * 行列のファイル出力
 * @param[in] fp ファイルポインタ
 * @param[in] frame フレーム番号
 * @param[in] matrix 行列を格納した配列
 * @param[in] nx,ny  行列の大きさ
 * @return 
 */
static void OutputMatrix(FILE *fp, int frame, double *matrix, int nx, int ny)
{
	fprintf(fp, "%d ", frame);
	for(int j = 0; j < ny; ++j){
		for (int i = 0; i < nx; ++i){
			fprintf(fp, "%f ", matrix[j*nx+i]); 
		}
	}
	fprintf(fp, "\n");
}

グリッドの線型補間

//-----------------------------------------------------------------------------
// 補間関数
//-----------------------------------------------------------------------------
inline int GET_INDEX(int i, int j, int k, int nx, int ny){ return k*nx*ny+j*nx+i; }
inline int GET_INDEX_2D(int i, int j, int nx){ return j*nx+i; }

/*!
 * 座標値から対応するグリッドを求める
 * @param[in] x,y 座標
 * @param[in] dx,dy グリッド幅
 * @param[in] nx,ny グリッド数
 * @param[out] i0,i1 x方向対応グリッド
 * @param[out] j0,j1 y方向対応グリッド
 * @param[out] s,t グリッド境界からの距離
 */
inline void GRID2D(const double &x, const double &y, const double &dx, const double &dy, const int &nx2, const int &ny2, 
				   int &i0, int &i1, int &j0, int &j1, double &s, double &t)
{
	double x0 = x/dx, y0 = y/dx;

	// (x,y)のグリッド位置
	i0 = (int)x0; i1 = i0+1;
	j0 = (int)y0; j1 = j0+1;

	s = (x0-i0);
	t = (y0-j0);

	// xがグリッド外のときの処理
	if(i0 < 0){
		i0 = 0; i1 = 1;
		s = 0.0;
	}
	if(i1 >= nx2){
		i0 = nx2-2; i1 = nx2-1;
		s = 1.0;
	}

	// yがグリッド外のときの処理
	if(j0 < 0){
		j0 = 0; j1 = 1;
		t = 0.0;
	}
	if(j1 >= ny2){
		j0 = ny2-2; j1 = ny2-1;
		t = 1.0;
	}
}

/*!
 * 座標値から対応するグリッドを求める
 * @param[in] x,y 座標
 * @param[in] dx,dy グリッド幅
 * @param[in] nx,ny グリッド数
 * @param[out] i0,i1 x方向対応グリッド
 * @param[out] j0,j1 y方向対応グリッド
 * @param[out] s,t グリッド境界からの距離
 */
inline void GRID3D(const double &x, const double &y, const double &z, const double &dx, const double &dy, const double &dz, 
				   const int &nx, const int &ny, const int &nz, int &i0, int &i1, int &j0, int &j1, int &k0, int &k1, double &s, double &t, double &u)
{
	double x0 = x/dx, y0 = y/dx, z0 = z/dz;

	if(x0 < 0.0) x0 = 0.0;
	if(y0 < 0.0) y0 = 0.0;
	if(z0 < 0.0) z0 = 0.0;

	// (x,y)のグリッド位置
	i0 = (int)x0; i1 = i0+1;
	j0 = (int)y0; j1 = j0+1;
	k0 = (int)z0; k1 = k0+1;

	s = (x0-i0);
	t = (y0-j0);
	u = (z0-k0);

	// xがグリッド外のときの処理
	if(i0 < 0){
		i0 = 0; i1 = 1;
		s = 0.0;
	}
	if(i1 > nx+1){
		i0 = nx; i1 = nx+1;
		s = 1.0;
	}

	// yがグリッド外のときの処理
	if(j0 < 0){
		j0 = 0; j1 = 1;
		t = 0.0;
	}
	if(j1 > ny+1){
		j0 = ny; j1 = ny+1;
		t = 1.0;
	}

	// zがグリッド外のときの処理
	if(k0 < 0){
		k0 = 0; k1 = 1;
		u = 0.0;
	}
	if(k1 > nz+1){
		k0 = nz; k1 = nz+1;
		u = 1.0;
	}
}


/*!
 * 線形補間による値の取得
 * @param[in] x,y 座標
 * @param[in] f フィールド値(double)が格納されている配列
 * @param[in] dx,dy グリッド幅
 * @param[in] nx,ny グリッド数
 * @return 線形補間値
 */
inline double LINEAR_INTERPOLATE_2D(const double &x, const double &y, double *f, const double &dx, const double &dy, const int &nx2, const int &ny2)
{
	int i0, j0, i1, j1;
	double s0, t0, s1, t1;

	GRID2D(x, y, dx, dy, nx2, ny2, i0, i1, j0, j1, s1, t1);

	s0 = 1.0-s1; 
	t0 = 1.0-t1; 

	// (x0,y0)における値を線形補間で求める
	return s0*(t0*f[GET_INDEX_2D(i0, j0, nx2)]+t1*f[GET_INDEX_2D(i0, j1, nx2)])+
		   s1*(t0*f[GET_INDEX_2D(i1, j0, nx2)]+t1*f[GET_INDEX_2D(i1, j1, nx2)]);
}

/*!
 * 線形補間による値の取得(3D)
 * @param[in] x,y,z 座標
 * @param[in] f フィールド値(double)が格納されている配列
 * @param[in] dx,dy,dz グリッド幅
 * @param[in] nx,ny,nz グリッド数
 * @return 線形補間値
 */
inline double LINEAR_INTERPOLATE_3D(const double &x, const double &y, const double &z, double *f, 
									const double &dx, const double &dy, const double &dz, 
									const int &nx, const int &ny, const int &nz)
{
	int i0, i1, j0, j1, k0, k1;
	double s0, s1, t0, t1, u0, u1;

	GRID3D(x, y, z, dx, dy, dz, nx, ny, nz, i0, i1, j0, j1, k0, k1, s1, t1, u1);
	s0 = 1.0-s1; 
	t0 = 1.0-t1; 
	u0 = 1.0-u1;

	// (x0,y0,z0)における値を線形補間で求める
	return u0*(s0*(t0*f[GET_INDEX(i0, j0, k0, nx+2, ny+2)]+t1*f[GET_INDEX(i0, j1, k0, nx+2, ny+2)])+ \
			   s1*(t0*f[GET_INDEX(i1, j0, k0, nx+2, ny+2)]+t1*f[GET_INDEX(i1, j1, k0, nx+2, ny+2)]))+ \
		   u1*(s0*(t0*f[GET_INDEX(i0, j0, k1, nx+2, ny+2)]+t1*f[GET_INDEX(i0, j1, k1, nx+2, ny+2)])+ \
			   s1*(t0*f[GET_INDEX(i1, j0, k1, nx+2, ny+2)]+t1*f[GET_INDEX(i1, j1, k1, nx+2, ny+2)]));

}

データ構造

ラベルとデータのマッピングクラス

stl::mapのラッパ.

//-----------------------------------------------------------------------------
//! ラベルとデータのマッピングを行うテンプレートクラス
//-----------------------------------------------------------------------------
template<class Type> 
class MapData
{
protected:
	map<string, Type> m_Map;	//!< ラベルとデータのマップ
	string m_strCurrentMap;		//!< 現在のデータを示すラベル

public:
	/*!
	 * ラベルnameのデータを検索して返す
	 * @param[in] name ラベル名
	 * @return nameに対応するデータ
	 */
	Type LookupData(const char *name)
	{
		map<string, Type>::iterator i = m_Map.find(name);

		if(i == m_Map.end())
			return NULL;
		else
			return m_Map[name];
	}

	/*!
	 * 現在のデータを取得 
	 * @return 現在のデータ
	 */
	Type GetCurrentData()
	{
		return m_Map[m_strCurrentMap];
	}

	/*!
	 * 現在のラベルを取得
	 * @return 現在のラベル
	 */
	string GetCurrentLabel()
	{
		return m_strCurrentMap;
	}

	/*!
	 * 現在のデータの設定
	 * @param[in] name 設定したいラベル
	 * @return 設定したデータ
	 */
	Type SetCurrentData(const char *name)
	{
		Type data = LookupData(name);

		if(data){
			m_strCurrentMap = name;
		}

		return data;
	}

	/*!
	 * データ作成
	 * @param[in] name ラベル
	 * @param[in] data データ
	 */
	void CreateData(const char *name, Type data)
	{
		Type data0 = LookupData(name);

		if(!data0){
			m_Map[name] = data;
			m_strCurrentMap = name;
		}
	}

	/*!
	 * 全データ削除
	 */
	void Clear(void)
	{
		m_Map.clear();
		m_strCurrentMap = "";
	}

	/*!
	 * キー文字列リストの取得
	 * @param[out] strs キー文字列リスト
	 */
	void GetStrings(vector<string> &strs)
	{
		map<string, Type>::iterator it;
		for(it = m_Map.begin(); it != m_Map.end(); ++it){
			strs.push_back(it->first);
		}
	}
};

トップ   編集 凍結 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2024-03-08 (金) 18:06:09