最近更新したページ
2013-10-20
2013-09-29
2013-09-23
2012-01-07
2011-11-09
2011-10-23
2011-10-09
2011-10-01
2011-09-29
2011-09-03
2011-08-07
2011-08-02
2011-07-29
2011-07-10
2011-05-05
2011-05-04
2011-04-24
2011-04-13
2011-04-05
2011-03-26
2011-02-18
2011-02-15
2010-12-26
2010-12-07
2010-12-05
2010-11-23
2010-09-28
2010-09-23
2010-08-26
2010-08-22
2010-07-16
2010-01-17
2010-01-11
2009-10-04
2009-08-21
2009-08-13
2009-06-18
2009-06-01
2009-04-29
2009-02-16
2009-02-11
2009-02-03
2008-07-22
2008-07-21
2008-07-15
2008-07-14
2008-07-13
2008-07-12
2008-07-08
2008-07-05
2008-06-28
2008-06-17
2008-06-05
2008-06-02
2008-06-01
2008-05-29
2008-05-26
2008-05-21
2008-05-19
2008-05-18
2007-10-31
2007-10-27
2007-09-28
2007-09-23
2007-09-17
2007-09-16
2007-09-14
2007-09-11
2007-06-18
2007-04-15
2006-12-21
2006-11-30
2006-11-22
2006-08-17
2006-03-29
2006-03-28
2006-03-27

C/C++ テストの実行


プログラムテスト


 この頁は、C/C++ ソート(並べ替え)ページから、「その他」の「テストデータ」と「実行時間計測」部分を独立させ、新規ページを作成・移動した内容です。

※横道にそれ、内容が肥大化した結果、新規ページが増えることが非常に多い。ソートの本筋になかなか戻れていない。

テストデータの作成


テストデータ作成関数の汎用化

 関数テンプレート、構造体配列、デフォルト引数...など、汎用的に利用可能な方向で徐々に修正中。

sample
#include <iostream>
#include <time.h>        // time()
#include <process.h>     // getpid()
#include <math.h>        // pow()
using namespace std;
struct object_data {     // テストデータを代入する構造体。
   int idx;
   int data;
};
// 小数点位置範囲の変換
// #define D_DIGIT      pow( (double)(10), (double)(-(digit)) )
// D_DIGIT の関数版:
double d_digit(const int in_digit) {
   double out_digit = pow( (double)(10), -(in_digit) );
   return out_digit;
}
// 引数のデフォルト値を使用しプリプロセッサ(マクロ)利用を極力排除。
// 取得乱数の初期設定(デフォルト引数)
// digit = 2 ---------> 例 -1->10 -1->10 0->1 1->.1 2->.01 3->.001
template < class T >
bool testArrData( T* srt_arr,          // 処理対象構造体配列
                  const int elements,  // 配列の要素数
                  const int digit     = 2,        // 小数点以下桁数
                  const int min       = 0,        // 乱数の最小値
                  const int max       = (10000+1) // 乱数の最大値
                )
{
   // 呼び出し毎に異なる乱数系列を発生
   srand( (unsigned)( time(NULL) + _getpid() ) );

   for (int i=0; i<elements; i++) {
      srt_arr[i].idx  = i + 1;
      srt_arr[i].data = rand() * rand();       // 0 〜 1,073,676,289
      srt_arr[i].data = (int)(srt_arr[i].data)
           % (int)( max - min ) + ( min );     // min〜max 整数の乱数
      srt_arr[i].data =
           /*( T )*/ // 注:適切にキャストしないと warning が出る
           ( srt_arr[i].data * (d_digit(digit)) );  // 桁調整(intなら不要)
   }
   return true; // 取り合えず 成否に関係なく true を返す。
}
void main(void) {
   const int arr_elm = 10;
   //int idx[arr_elm];
   //int arr_tbl[arr_elm];
   struct object_data dat[arr_elm];

   cout << "■1. テストデータ代入" << endl;
   testArrData(dat, arr_elm);
   cout << "■2. 代入データ表示" << endl;
   for(int i=0; i < arr_elm; i++) {
      printf("idx[%3i]:%3i \n", dat[i].idx, dat[i].data);
   }
   cout << "■3. 終了" << endl;
}
※大きな問題点。特定の構造体専用となってしまっている。
※このままでは、.h とすることも出来ず(出来るが意味無)汎用性も皆無。

表示サンプル
■1. テストデータ代入
■2. 代入データ表示
idx[  1]: 49
idx[  2]: 86
idx[  3]: 43
idx[  4]: 59
idx[  5]: 21
idx[  6]: 58
idx[  7]: 38
idx[  8]: 57
idx[  9]: 81
idx[ 10]: 92
■3. 終了
続行するには何かキーを押してください . . .
※一応動いた。

▲上へ [ 編集 ]

テストデータ作成関数を作る


 関数でもクラスでもよいが、毎度作成するのも面倒なので取り合えず関数化。

sample2-3: sample2-2 の関数化バージョン
#include <stdlib.h>      // srand() rand()
#include <time.h>        // time()
#include <unistd.h>      // getpid()
#include <math.h>        // double floor(double n) (切捨て処理)

#define RND_N_DEV    100 // digit指定:小数点以下第二位
#define EXPECTED_MIN 140
#define EXPECTED_MAX 400

bool testArrData(double* rnd_n, int rnd_max) {
   // srand((unsigned)(time(NULL)+getpid()));
   srand(1); // 乱数初期値セット

   for (int i=0; i<rnd_max; i++) {
      rnd_n[i] = rand() * rand();           // 〜 1,073,676,289
      rnd_n[i] = floor(rnd_n[i]/10);        // 〜   107,367,628(桁落し)
      rnd_n[i] = (int)(rnd_n[i])            // 14000〜40000 擬似乱数取得
               % (((EXPECTED_MAX-EXPECTED_MIN)*RND_N_DEV)+1)
               + (EXPECTED_MIN * RND_N_DEV);
      rnd_n[i] = rnd_n[i] / (RND_N_DEV);    // 桁調整 140.00〜400.00
   }
   return true;                             // 取り合えず true を返す。
}
※動作未確認済み
#include <iostream>

void main() {
   const int max_index_value = 65536;     // 配列要素数
   double test_data_arr[max_index_value]; // 配列の作成

   // --- テストデータ作成関数の呼出
   bool rand_arr_flag = testArrData(test_data_arr, max_index_value);

   // --- テストデータ配列表示
   for (int i=0; i<max_index_value; i++) { 
      printf("test_data_arr[%05d] = %9.2f \n",i,test_data_arr[i]);
   }
}
※動作確認済み
test_data_arr[00000] =    377.12
test_data_arr[00001] =    284.55
test_data_arr[00002] =    201.76
〜 中略 〜
test_data_arr[65533] =    308.12
test_data_arr[65534] =    317.63
test_data_arr[65535] =    359.60
続行するには何かキーを押してください . . .
※output data sample view

▲上へ

実用的な擬似乱数の作成

 sample1 を元に、(1)double型、(2)小数点以下第二、(3)偶数/奇数 の偏りを出来るだけ廃し、(4)140.00〜400.00 までの擬似乱数を取得する方法を考えてみる。

sample2-2: 140.00〜400.00 の double型テスト用データ配列を作成
#include <iostream>
#include <stdlib.h>    // srand() rand()
#include <time.h>      // time()
#include <unistd.h>    // getpid()
#include <math.h>      // double floor(double n) (切捨て処理)

#define RND_N_MAX 100000+1
#define RND_N_DEV 100
#define EXPECTED_MIN 140
#define EXPECTED_MAX 400

void main(void) {

   const int rnd_max = 100000;
   double rnd_n[rnd_max];
   // srand((unsigned) (time(NULL) + getpid())); // 乱数初期値セット
   srand(1); // 乱数初期値セット

   for (int i=0; i<rnd_max; i++) {
      rnd_n[i] = rand() * rand();             // 〜 1,073,676,289
      rnd_n[i] = floor(rnd_n[i]/10);          // 〜   107,367,628(桁落し)
      rnd_n[i] = int(rnd_n[i]) % (RND_N_MAX); // 範囲限定
      rnd_n[i] = rnd_n[i] / (RND_N_DEV);      // 桁調整
      // output 再調整
      rnd_n[i] = int(rnd_n[i] * RND_N_DEV)
               % ((EXPECTED_MAX - EXPECTED_MIN) * RND_N_DEV + 1 )
               + (EXPECTED_MIN * RND_N_DEV);
      rnd_n[i] = rnd_n[i] / (RND_N_DEV);      // 再調整桁調整
   }
   for (int i=0; i<rnd_max; i++) { 
      printf("rnd_n[%05d] = %09.3f \n",i,rnd_n[i]);
   }
}
※このまま VC では動かないので注意。※ unistd.h は VC に無い。
※範囲限定は未だしていない。ここで出る値は 0.00〜1000.00 である。
※範囲指定実行。140.00〜400.00 の間で値を取得。
※冗長だが、乱数 100000件程度なら瞬間で終わる。※表示は掛かるので注意。


  • 要件を満たすための覚書き
    • (1)double型 の乱数を取得する?
      rand() は、int型である。double型へのキャスト、又は、意図した計算結果を取得できるよう配慮が必要。
    • (4)140.00〜400.00 の値を取得する?
      RAND_MAX=32,767。単純に小数点以下含めた乱数を取得するのに足りない。
      rand() * rand() とすることで擬似乱数の取得範囲を拡大する。
      ※偶数・奇数のバランスが崩れるのを配慮する必要->(3)の問題を抱えることになる。-> 範囲適用の計算。
      ※剰余 % の計算対象は int 型であることに注意。
      • ※例1: 0-100 の擬似乱数取得 -> rand()%(100+1);
      • ※例2:10〜20 の擬似乱数取得 -> rand()%(20-10+1)+10;
      • (2)小数点以下第二を取得する?
        単純に100で割ってdouble型変数に代入すれば良い。
    • (3)偶数/奇数 の偏りを廃す?
      ※1000で割った値の小数点第2位以下切捨てでは?
      ※最小値の出現率が?(10)倍になる…ようである。※最小値の出現バランスが崩れる模様…
      ※rand() の2番目が偶数の場合何らかの対処をすればよいと思うが、面倒なのでこのまま使用。

▲上へ

乱数(擬似乱数)の基本

※覚書き
 実際には「擬似乱数」となり、初期データが同じなら全く同じデータが出る。初期データに日時などを指定することで常に異なる擬似乱数として使用する。

sample2-1:rand(),srand() 乱数の取得(乱数を使ったテスト用データ配列の作成)
〜
#include <stdlib.h>    // srand() rand()
#include <time.h>      // time()
#include <unistd.h>    // getpid() win→ <process.h>
〜
   const int rnd_max = 256;
   int rnd_n[rnd_max];
   //srand( (unsigned) time(NULL));             // 1).乱数初期値
   //srand( (unsigned) (time(NULL)+getpid()) ); // 2).乱数系列 2
   srand(1);                                    // 3).同一乱数系列
   // 任意の乱数を rnd_max 回発生
   for (int i=0; i<rnd_max; i++) { 
      rnd_n[i] = rand();                // 4).(取得値)0~RAND_MAX
      // rnd_n[i] = rand() % (100+1);   // 5).(取得値)0~100
      // rnd_n[i] = rand() % (50+1)+50; // 6).(取得値)50~100
      // rnd_n[i] = (rand()*rand());    // 7).大きな乱数を取得したい場合
   }
〜
※動作確認済み。
unistd.h を作成し #include <process.h> とすれば汎用的ソースとなる。また、worning err は、#define getpid _getpid とし回避可能。(※getpid()は非推奨表示)

参考:関数テンプレート
void srand(unsigned int seed);
int rand(void);

  • 乱数の取得値を指定する
    • 4).0〜RAND_MAX(stdlib.h->0x7fff(32767))の間で値を取得する。
    • 5).0〜指定値の間で、値を取得する。
    • 6).指定値〜指定値の間で、値を取得する。
    • 7).昔のN8xBASIC 等は、浮動小数点以下の長乱数を取得していた気(あくまで気…)がするが、RAND_MAX=32767 は小さいと思う場合、または、長い浮動小数点型の乱数が必要な場合、こんな感じて大きな値を取得可能。
      • ※偶数値の出現比率が増えるので工夫が必要。(偶数掛ければ必ず偶数 ???3/4が偶数になってしまう??? )
      • ※?:下1桁カット、計算過程で調整、下一桁四捨五入し10で割るとか …
      • short int:-32,768~32,767,(unsigned)0~65,535 であることに注意。
        long:-2,147,483,648~2,147,483,647,(unsigned)0~4,294,967,295
        (rand()*rand())=max 1,073,676,289 -> long int なら収まる。(通常:int==long int 参考:http://wiki.livedoor.jp/cafeboy1/d/C/C%2b%2b%20%a4...
  • 乱数の初期値(乱数系列)
    • 1).では、別の場所(他のPC)で、同じ時間(日時)、同じ方法でサイコロを振ると(乱数取得)すると、同じ目が出るという不思議な現象が発生すると思われる。
    • 2).では、時間+pid のため 1).の問題は発生しないが、process.h(UNIX系は unistd.h) も #include する必要がある。
    • 3).毎回同一(擬似的な)乱数が発生する。srand() の値が同一では、全く同じ値を毎回、同じ順番で発生するので注意。要するに srand( 乱数 ) で有る必要があるが、そんなの無理(乱数の取得に乱数が必要!)なので"日付"とか"pid"とかで代用する。

▲上へ

実行速度の計測


sample1-2: 実行時間の計測
// sampleTime.cpp
#include <windows.h>             // mmsystem.h <- UINT で使用
#include <mmsystem.h>            // timeGetTime()
#pragma comment(lib,"winmm.lib") // timeGetTime()
   〜
   int arrTbl[] = { 90,80,85,70,30,… };
   〜
   timeBeginPeriod(1);                        // 精度 1ms
   unsigned long tc_start = timeGetTime();    // 計測開始時間取得
   // --------------------------------------> (計測開始)
   sort(arrTbl, arrTbl+13);
   // --------------------------------------> (計測終了)
   unsigned long tc_end   = timeGetTime();    // 計測終了時間取得
   printf("Time = %d\t \n\n", tc_end - tc_start);
   timeEndPeriod(1);                          // 精度復元
   〜
※timeBeginPeriod(x) は、システム全体の精度へ影響を与えるとのことより、必ず timeEndPeriod(x) で使用後に元へ戻す必要あり。(x は同じ値を指定)

sample1-1; 実行時間の計測
// sampleTime.c / .cpp
#include <time.h>
   〜
   int arr[] = { 12, 26, 32, … };
   int as = sizeof(arr)/sizeof(arr[0]);
   〜
   clock_t tc_start, tc_end;
   // clock_t time.h -> typedef long clock_t(system依存有)
   〜
   tc_start = clock();
   // -------------------------------->  (計測開始)
   qsort(arr, as, sizeof(int), compare);
   // -------------------------------->  (計測終了)
   tc_end   = clock();
   〜
   printf("Time=%.4f\n\n",(double)(tc_end-tc_start)/CLOCKS_PER_SEC);
   // time.h -> #define CLOCKS_PER_SEC 1000  (system依存有)
※精度を求めないならこの方が簡単そう。

 これ以外にも精度重視や精度が落ちてもシステムに負担をかけないとか、計測方法がいろいろとあるようである。必要に応じ選択することとなるようだが、この2つ程度知ってれば問題ないものとし、時間計測はとりあえず終了!
 (大概、1つの方法しか使用しないので・・・)

▲上へ

リンク


内部リンク


外部リンク


  • 現在ありません

▲上へ
2008年07月05日(土) 22:34:19 Modified by cafeboy1




スマートフォン版で見る