c++ builder > 複数回条件が成立したかどうかの実装 > double型の範囲内/範囲外チェック

```txt:動作確認
C++ Builder XE4
```

http://qiita.com/7of9/items/9c9964a7a7fc24d7d384
で検討していた実装を行った。

double型の値が指定の条件を連続して成立しているかチェックする。

static関数CUtilContinuousDoubleCondition::Test_Condition()実行で動作確認する。


### code

```UtilContinuousDoubleCondition.h
//---------------------------------------------------------------------------
#ifndef UtilContinuousDoubleConditionH
#define UtilContinuousDoubleConditionH

//---------------------------------------------------------------------------

/*
連続して条件が成立しているかどうかのチェック
*/

class CUtilContinuousDoubleCondition {
private:
	static const int kMaxnumData = 10; // データ格納最大数 (10: 任意)

	int m_checkCount; // チェックする個数
	// Condition
	double m_minMax[2]; // min, max
	int m_rangeType; // Range_eを格納する
	// Data
	int m_dataCount;
	double m_dataList[kMaxnumData];

	// テスト関数
	bool __fastcall test_inrangeValid();
	bool __fastcall test_outrangeValid();

public:	
	typedef enum tag_Range {
		RANGE_INSIDE,
		RANGE_OUTSIDE,
	} Range_e;

	void __fastcall SetCheckCount(int cnt);
	void __fastcall SetCondition(double dmin, double dmax, int rngTyp);
	void __fastcall PushData(double dta);
	void __fastcall ClearData();
	bool __fastcall IsEstablished();

	// テスト関数
	static void __fastcall Test_Condition();
	
	// Constructor
	__fastcall CUtilContinuousDoubleCondition();
};

#endif
```

```UtilContinuousDoubleCondition.cpp
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include <memory>
#include "UtilContinuousDoubleCondition.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)


#define DEBUG_DO_PRINT // デバッグ出力

/*
v0.2 2016/01/27
	double型への対応
	- 不使用変数、関数の除去
	- SetCondition()の引数を変更した > [最小, 最大, 範囲のタイプ]
	- [Range_e]追加
	- double型に対する変数名、関数名の書き換え
	- UtilContinuousboolCondition v0.1 より分岐

----------------------------------	
v0.1 2016/01/26 [UtilContinuousboolCondition.cpp]
	bool型への対応
	- Test_BoolCondition()追加
	- IsEstablished()追加
	- boolデータ追加
		+ clearBoolData()追加
		+ m_boolDataList[]追加
		+ [m_boolDataCount]追加
	- boolフラグ条件追加
		+ m_boolFlags[]追加
		+ [m_boolFlagCount]追加
	- SetConditionBool()追加
 	- [typeIndex_e]追加
	- SetCheckCount()追加
	- [m_checkCount]追加
	- [Condition_e]追加
	- debug_outputDebugString()追加
*/

static const double kDefaultDoubleData = 0.0;

//---------------------------------------------------------------------------
// ファイルスコープstatic関数
static void debug_outputDebugString(String prefix, String msg)
{
	// あとでまとめてデバッグ出力をコメントアウトするため、関数にしている。

#ifdef DEBUG_DO_PRINT
	String work = L"UtilContinuousDoubleCondition >" + prefix + L": " + msg;
	OutputDebugString(work.c_str()); // @ debug_outputDebugString
#endif
}

//---------------------------------------------------------------------------
// コンストラクタ、デストラクタ
__fastcall CUtilContinuousDoubleCondition::CUtilContinuousDoubleCondition()
{
	m_checkCount = 0;
	m_dataCount = 0;
	ClearData();
}
//---------------------------------------------------------------------------
// その他の関数

void __fastcall CUtilContinuousDoubleCondition::ClearData()
{
	for(int idx = 0; idx < kMaxnumData; idx++) {
		m_dataList[idx] = kDefaultDoubleData;
    }
    m_dataCount = 0;
}

void __fastcall CUtilContinuousDoubleCondition::SetCheckCount(int cnt)
{
	m_checkCount = cnt;	
}

void __fastcall CUtilContinuousDoubleCondition::SetCondition(double dmin, double dmax, int rngTyp)
{
	m_minMax[0] = dmin;
	m_minMax[1] = dmax;
	m_rangeType = rngTyp;
}

void __fastcall CUtilContinuousDoubleCondition::PushData(double dta)
{
	m_dataList[m_dataCount] = dta;
	m_dataCount++;
	if (m_dataCount > m_checkCount) {
		for(int idx = 0; idx < m_checkCount; idx++) {
			m_dataList[idx] = m_dataList[idx + 1];
		}
		m_dataCount--;
	}
}

bool __fastcall CUtilContinuousDoubleCondition::test_inrangeValid()
{
	SetCheckCount(3);
	// 最後の設定が有効
	SetCondition(3.1415, 6.022, RANGE_INSIDE);
	SetCondition(2.7182, 3.1415, RANGE_INSIDE); // 有効

	// 成立が連続してない例
	PushData(4.0);
	PushData(3.0); // 有効
	PushData(4.0); // 有効
	PushData(3.0); // 有効
	bool estb1_1 = IsEstablished(); // false

	// 成立が連続している例
	PushData(3.0); // 有効
	PushData(3.0); // 有効
	PushData(3.0); // 有効
	bool estb1_2 = IsEstablished(); // true

	return (estb1_1 == false) && (estb1_2 == true);
}

bool __fastcall CUtilContinuousDoubleCondition::test_outrangeValid()
{
	SetCheckCount(3);
	// 最後の条件だけ使われる
	SetCondition(2.7182, 3.1415, RANGE_INSIDE);
	SetCondition(2.7182, 3.1415, RANGE_OUTSIDE); // 有効

	// 成立が連続してない例
	PushData(2.0);
	PushData(4.0); // 有効
	PushData(2.0); // 有効
	PushData(3.0); // 有効
	bool estb2_1 = IsEstablished(); // false

	// 成立が連続している例
	PushData(2.0); // 有効
	PushData(4.0); // 有効
	PushData(2.0); // 有効
	bool estb2_2 = IsEstablished(); // true

	return (estb2_1 == false) && (estb2_2 == true);
}


/*static*/ void __fastcall CUtilContinuousDoubleCondition::Test_Condition()
{
	CUtilContinuousDoubleCondition *cntCnd = new CUtilContinuousDoubleCondition();

	bool inrange;
	inrange = cntCnd->test_inrangeValid();

	bool outrange;
	outrange = cntCnd->test_outrangeValid();

	delete cntCnd;
	cntCnd = NULL;
}

bool __fastcall CUtilContinuousDoubleCondition::IsEstablished()
{
	if (m_checkCount == 0 || 
		 m_dataCount < m_checkCount) {
		return false;
	}

	double dmin = m_minMax[0];
	double dmax = m_minMax[1];
	for(int idx = 0; idx < m_checkCount; idx++) {
		if (m_rangeType == RANGE_INSIDE) {
			if(m_dataList[idx] < dmin || m_dataList[idx] > dmax) {
				return false;
			}
		}
		if (m_rangeType == RANGE_OUTSIDE) {
			if(m_dataList[idx] >= dmin && m_dataList[idx] <= dmax) {
				return false;
			}
		}
	}
	return true;
}
```

### 備考

- double型のみ対応
- bool型を先に実装して、double型実装を行ったが、実装の作り直しの罠にはまった
- Fortran, PowershellなどのGE, LTなどを使おうとしたが、片方ずつ設定で失敗した
- 現在の実装にinteger, bool型対応を追加するか（万能クラスにするか）、個別実装にするかは要検討
- IDE依存性をなくす実装にしてもいいかもしれない（今すぐにはやらない)


## 改良版へのリンク

C++の機能を使って改良された方がおられる。色々勉強になります。

[連続的条件成立検知](http://qiita.com/SaitoAtsushi/items/d26a5cfa5453d8d91b63#_reference-38d77bd027523b2e4647)