ポコム プログラマーズ ガイド

目次

第1章 ポコムとは

ポコム(POrtable COMpiler)は C/C++ を使った、小型のフレームワークです。 数値計算、なかでも待ち行列網、グラフ理論や統計分析に向いています。 ポコムは軽くて速いプログラムを、 手っ取り早く開発するのに向いています。 ポコムを使う効果はつぎのとおりです。

ポコムが供給するファイルはつぎのとおりです。

pocom.htmlこのファイル
pocom.h ポコムのシステムを記述した C 言語ファイル
Example.c 連立方程式を解く例題
test.txt 例題データ ファイル

第2章 ポコムによる開発例

「連立方程式を解く」という例題を用いて、 ポコムの簡単な開発例を示します。 例題はN=3個の未知数 X[0]、X[1]、X[2] についての連立方程式

      A[0][0]*X[0] + A[0][1]*X[1] + A[0][2]*X[2] == B[0]
      A[1][0]*X[0] + A[1][1]*X[1] + A[1][2]*X[2] == B[1]
      A[2][0]*X[0] + A[2][1]*X[1] + A[2][2]*X[2] == B[2]

を解きます。(係数行列 A[ ][ ] と B[ ] は与えられる) 説明は、つぎのような順序で示します。

これから示す例題は次のようなデータ ファイル test.txt を使います。

         A                         B
           2.000   5.000   7.000 ;  23.000
           4.000  13.000  20.000 ;  58.000
           8.000  29.000  50.000 ; 132.000 $
        Solve
        Print N A X B

そして、次のように計算をし、結果を出力します。( X が解です)

        C:\>Example test.txt
         N  A                         X       B     
          3   2.000   5.000   7.000 ;   3.000  23.000
              4.000  13.000  20.000 ;   2.000  58.000
              8.000  29.000  50.000 ;   1.000 132.000 $

; は行列の行末を表します。$ は配列の終わりを表します。 データ ファイルで配列 A を処理すれば、変数 N は自動的に設定されます。 ポコムでは入力ファイルと出力ファイルの形式は同じです。

以下に、ポコムのプログラム(Example.c)を示します。

   /* Example.c */
   #define FILE_NAME "Example.c"

   #if defined(PDEF_H)

    INT(N,3,       "Size of matrix")
    RMAT(A,307,N,N,"Coefficient matrix")
    RVEC(B,307,N,  "Right side vector")
    RMAT(C,307,N,N,"Work matrix")
    RVEC(X,307,N,  "Solution vector")
    PROC(Solve,    "Solve linear equation")

   #else

    #include "pocom.h"
    CHECK_FILE_NAME

    void Solve(void) {
        Int i,j,k;
        Check("A B"); Alloc("C X");
        for (i=0;i<N;i++) for (j=0;j<N;j++) C[i][j]=A[i][j];
        for (i=0;i<N;i++) X[i]=B[i];
        for (k=0;k<N;k++) {
            if (C[k][k]==0) Error("Solve","Denominator is 0");
            for (j=k+1;j<N;j++) C[k][j]/=C[k][k];
            X[k]/=C[k][k];
            for (i=0;i<N;i++) if (i!=k) {
                for (j=k+1;j<N;j++) C[i][j]-=C[i][k]*C[k][j];
                X[i]-=C[i][k]*X[k];
            }
        }
    }

   #endif
マクロ FILE_NAME に、必ずそのファイル自身のファイル名を指定します。 (以前のバージョンでは THIS_IS マクロで指定していて、現在でも引き続き使用できますが、 トラブルを防ぐため、よりチェックの厳しい FILE_NAME マクロを使用することを推奨します。)

2.1 データ構造の記述

ポコムは17種類のデータ型を用意しています。ここではその一部を紹介します。 他のデータ型は第4章 データの種類を参照してください。

「連立方程式を解く」のには、どのような変数が必要でしょうか?。 もちろん、係数行列が必要です。そして、行列の大きさを示す整数も必要です。 N が行列の大きさを示し、A が係数行列を示し、B に方程式の右辺が入り、 X に未知数が求まります。また、作業用に行列 C も使います。 計算ルーチンも変数と同様に宣言します。 ここでは、Solve を計算を実行する C 言語の関数名とします。 ポコム用にこれらのデータ構造を書くと、

    INT(N,3,       "Size of matrix")
    RMAT(A,307,N,N,"Coefficient matrix")
    RVEC(B,307,N,  "Right side vector")
    RMAT(C,307,N,N,"Work matrix")
    RVEC(X,307,N,  "Solution vector")
    PROC(Solve,    "Solve linear equation")

のようになります。これらを左から順に説明します。

各行の最初の INT、RMAT、RVEC、PROC は C 言語のマクロです。 ポコムで変数や関数を宣言する時は、必ずこれらのマクロを使います。 INT は整数型を示し、RMAT は浮動小数点の行列を示し、 RVEC は浮動小数点のベクトルを示しています。

次の N、A、B、C、X、Solve は、プログラムで使用する名前を決めています。 これは、_ で終わってはいけません。 これらの名前は、計算ルーチンで、 大域整数変数や関数として、扱うことができます。

N は Int N; と宣言されます。 これは、通常の場合 int N; と宣言したのと同じで、 #include "pocom.h" の前に #define INT_64 とすると、 long long N; と宣言したのと同じになります。(Visual C++なら __int64) ポコムの以前のバージョンでは常に int としていましたが、新しいポコムでは Int 型を使います。 32ビットと16ビットのコンパイラでは int 型が一番高速な型でしたが。 64ビットのコンパイラでは int 型よりも long long 型の方が高速になることがあるので、 新しく導入しました。

さらに16ビットのコンパイラで、 #include "pocom.h" の前に #define INT_32 とすると、 long N; と宣言したのと同じになります。

A は double**A; のように宣言したことになります。 (厳密にはコンパイラによって double*const __restrict*__restrict A; となります) 例えば、行列 A の転置行列Cを作るルーチンでは、

        for (i=0;i<N;i++) for (j=0;j<N;j++) C[i][j]=A[j][i];

のように書くことができます。

計算ルーチン Solve を PROC マクロで登録すると、 同じ名前の C 言語の関数 Solve( ) は、 データ ファイルから呼び出すことができるようになります。 ポコム関数 Print や Load も同様に C 言語で記述された関数です。 しかし、これらは、pocom.h に記述されています。

次の数字、2 と 307 は、データを表示する時の桁数を決めています。 関数の宣言では指定しません。 この 2 はスペースを含まない最大の桁数を指定しています。 したがって N は -9 から 99 までは桁ずれを起こさずに表示できます。 数字の下位2桁のみが桁数として有効です。 百の桁は、小数点以下の桁数を表すのに使われます。 307 は小数点以下3桁、全体で7桁を使って表示することを意味しています。 この桁数はポコム関数 Format により、 実行時に変更できます。

RMAT と RVEC の中央にある N は、 行列の大きさが整数変数 N で決まることを表しています。 ポコムでは、どんな種類の配列でも、大きさは変数で決まります。 配列以外の単純型の宣言では大きさは指定しません。

最後の"Size of matrix"は、 ファイルを指定せずに起動する時に表示されるコメントを決めています。 "Coefficient matrix"...も同様です。
これを、コメントだけを表示しない場合は空文字列、"" あるいは ZeroStr とします。
0(NULL) にすると、ファイルを指定せずに起動する時に変数の表示の一覧から除外されます。
英語と日本語の両方に対応するには。 以下のように EJ マクロを使います。コンパイル時に JPN マクロが0以外だと、 EJ マクロは日本語のメッセージを有効にし、JPN マクロが定義されていなかったり、 0と定義されていれば英語のメッセージを有効にします。プログラムに日本語を 埋め込む場合はできるだけ EJ マクロを使って日本語が使えないときに備えて下さい。 具体的には Windows で /D UTF8 を定義したり、-DUTF8 と定義したりして UTF8 のデータファイルに対応させようと する場合にプログラムに日本語が埋め込まれると、UTF8 に対応していないコンパイラ を使うと文字化けが起きるので、JPN は自動的に無効になります。 なお、JPN が無効な時は、データファイルの文字コードから推測して、出力 桁数を調整するようになります。一方、JPN が有効な時は pocom.h の文字コードに 従って出力桁数を調整します。

    INT(N,3,       EJ("Size of matrix",       "行列の大きさ"    ))
    RMAT(A,307,N,N,EJ("Coefficient matrix",   "係数行列"        ))
    RVEC(B,307,N,  EJ("Right side vector",    "右辺"            ))
    RMAT(C,307,N,N,EJ("Work matrix",          "作業用の行列"    ))
    RVEC(X,307,N,  EJ("Solution vector",      "計算結果"        ))
    PROC(Solve,    EJ("Solve linear equation","連立方程式を解く"))

2.2 計算ルーチンの記述

計算ルーチン部分を以下に示します。

    #include "pocom.h"
    CHECK_FILE_NAME

    void Solve(void) {
        Int i,j,k;
        Check("A B"); Alloc("C X");
        for (i=0;i<N;i++) for (j=0;j<N;j++) C[i][j]=A[i][j];
        for (i=0;i<N;i++) X[i]=B[i];
        for (k=0;k<N;k++) {
            if (C[k][k]==0) Error("Solve","Denominator is 0");
            for (j=k+1;j<N;j++) C[k][j]/=C[k][k];
            X[k]/=C[k][k];
            for (i=0;i<N;i++) if (i!=k) {
                for (j=k+1;j<N;j++) C[i][j]-=C[i][k]*C[k][j];
                X[i]-=C[i][k]*X[k];
            }
        }
    }

pocom.h をインクルードした直後に CHECK_FILE_NAME を書きます。 これは、FILE_NAME マクロのファイル名が本当に、それ自身のファイル名かどうか 確認するのに必要です。

関数 Check("A B") は、指定した配列のサイズが矛盾した場合、 エラー メッセージを表示して、プログラムを終了します。 Check( ) は暴走しないプログラムを書くためには、非常に重要な関数です。 後で詳しく説明します。

関数 Alloc("C X") は指定した配列変数に必要なメモリを確保します。 この関数もエラーが起きれば中止します。 例えば、サイズを示す変数がマイナスであったり、 MS-DOS ならば、メモリが足りなくなった時にエラーになります。 Alloc( ) で確保された領域は0で初期化されます。 ただし、文字列の場合は、長さ0の文字列定数 ZeroStr を指します。 Alloc( ) は、以前に確保されていた領域をいったん解放し、 その後、新しい領域を確保します。

関数 Error( ) は2つのエラーメッセージを表示して、 プログラムを終了します。英語にも日本語にも対応するには以下のようにします。

         if (C[k][k]==0) Error("Solve", EJ("Denominator is 0","分母が0"));

2.3 データ読み込みの順序

データファイルにおいて、変数の順序にはある程度自由度があります。 以下のようなデータファイルでも、結果は最初の例と変わりはありません。

        N  B        A
         3  23.000   2.000   5.000   7.000 ;
            58.000   4.000  13.000  20.000 ;
           132.000   8.000  29.000  50.000 $
        Solve
        Print N A X B

一度に指定する必要もなく、以下のように分けて書くことも、 内容を変更して繰り返し書くことも可能です。

        A
          2.000   5.000   7.000 ;
          4.000  13.000  20.000 ;
          8.000  29.000  50.000 $

        B
         23.000  58.000 132.000 $

        Solve
        Print N A X B

        B
        132.000  58.000  23.000 $

        Solve
        Print X

ここで、エラーのあるデータファイルの例を示します。

        A
          2.000   5.000   7.000 ;
          4.000  13.000  20.000 ;
          8.000  29.000  50.000 $

        B
         23.000  58.000 40.000 132.000 $

        Solve
        Print N A X B

変数AとBは共に変数Nで大きさが決まっています。 Aを読み込んだときはNは3になるのに、Bを読み込むとNは4になります。 計算ルーチンSolveでNが4であると、行列Aを処理するときに、 Aの範囲を外れた場所にアクセスして、プログラムが暴走する危険があります。

この暴走の危険を回避するためにあるのが、関数 Check( )です。 このデータファイルを処理した時のエラーメッセージは以下のようになります。

        test.txt(9)でエラーが発生!
        7|   23.000  58.000 40.000 132.000 $
        8|
        9| Solve
        Check("A B")
               ^
        A:'B'によってサイズ'N'が 3 から 4 へ変化した

Check( ) はこのように原因を詳しく報告します。

2.4 配列の大きさを計算ルーチンで指定する場合

最初に説明した開発例で作業用行列 C は N×N でしたが、 これを N×(N+1) にするとより簡素に計算ルーチンを書くことができます。 この場合、新たに N+1 を表す整数変数NP1を作り、行列 C の列サイズとします。 そして、行列 C を Alloc( ) するまえに、NP1 に N+1 を代入しておきます。

また、ここでは文字列変数 Debug を使った、途中経過の表示の例も示します。

AUTO はプログラムが起動された時に自動的に実行されるデータを決めます。 ここでは、ポコム関数 Range を呼び出して、 N は0以上という制限を加えています。 これにより、配列が読まれなかった場合、 N は初期値0のままなので Check("A B") ; でエラーメッセージが表示されるようになります。

AUTO は変数の初期値を設定する時にも使います。

さらに INT(N,3,EJ("Matrix size","行列の大きさ")) を INTF(N,3,10,EJ("Matrix size","行列の大きさ")) のように書くと N が 10 以外の値になることを 防ぐことができます。 (FIX は以前は INTF と同じでしたが、現在は異なります)

また、初期化処理など、起動時に実行したい処理がある場合は、 その処理を行う関数を用意して、AUTO で呼び出すようにします。

   /* Example2.c */
   #define FILE_NAME "Example2.c"

   #if defined(PDEF_H)

    INT(N,3,         EJ("Size of matrix",       "行列の大きさ"    ))
    INT(NP1,3,       "N + 1")
    INT(K,3,         EJ("Loop control variable","ループの制御変数"))
    STR(Debug,5,     EJ("Outputs for Debug",    "デバッグ用の出力変数名"))
    RMAT(A,307,N,N,  EJ("Coefficient matrix",   "係数行列"        ))
    RVEC(B,307,N,    EJ("Right side vector",    "右辺"            ))
    RMAT(C,307,N,NP1,EJ("Work matrix",          "作業用の行列"    ))
    RVEC(X,307,N,    EJ("Solution vector",      "計算結果"        ))
    PROC(Solve,      EJ("Solve linear equation","連立方程式を解く"))
    AUTO("Range N > 0")

   #else

    #include "pocom.h"
    CHECK_FILE_NAME

    void Solve(void) {
        Int i,j;
        Check("A B"); NP1=N+1; SizeChangedBy(NP1,Solve); Alloc("C X");
        for (i=0;i<N;i++) for (j=0;j<N;j++) C[i][j]=A[i][j];
        for (i=0;i<N;i++) C[i][N]=B[i];
        for (K=0;K<N;K++) {
            if (C[k][k]==0) Error("Solve", EJ("Denominator is 0","分母が0"));
            for (j=K+1;j<=N;j++) C[K][j]/=C[K][K];
            for (i=0;i<N;i++) if (i!=K) 
                for (j=K+1;j<=N;j++) C[i][j]-=C[i][K]*C[K][j];
            if (*Debug) Print(Debug);
        }
        for (i=0;i<N;i++) X[i]=C[i][N];
    }

   #endif

test.txt
     Debug
	 'K C'

      A                         B
        2.000   5.000   7.000 ;  23.000
        4.000  13.000  20.000 ;  58.000
        8.000  29.000  50.000 ; 132.000 $

     Solve
     Print N A X B

出力結果
     K   C
       0   2.000   2.500   3.500  11.500 ;
           4.000   3.000   6.000  12.000 ;
           8.000   9.000  22.000  40.000 $

     K   C
       1   2.000   2.500  -1.500   1.500 ;
           4.000   3.000   2.000   4.000 ;
           8.000   9.000   4.000   4.000 $

     K   C
       2   2.000   2.500  -1.500   3.000 ;
           4.000   3.000   2.000   2.000 ;
           8.000   9.000   4.000   1.000 $

     N   A                         X       B
       3   2.000   5.000   7.000 ;   3.000  23.000
           4.000  13.000  20.000 ;   2.000  58.000
           8.000  29.000  50.000 ;   1.000 132.000 $

SizeChangedBy(NP1,Solve); はこの例では意味を持ちません。ただ、習慣として書いておきます。
例えば、NP1 が他の配列のサイズになっていて、関数 Solve( ) によって整合性が取れなくなった場合を考えます。
ほかの計算ルーチンで Check( ) がその矛盾を発見した時に、その原因が Solve( ) であることを報告するのに、 SizeChangedBy(NP1,Solve); は役立ちます。

AUTO は Range で変数の範囲を指定する以外にも、 Alias で変数に日本語の別名をつける時にも便利です。

次の節で、AUTO のさらに高度な使い方を説明します。

2.5 データファイルを埋め込む場合

データを別ファイルに書かずに、データをプログラムに埋め込んで計算を実行したい場合があります。 それを実現する定義の例(Example3.c)を示します。

   /* Example3.c */
   #define FILE_NAME "Example3.c"

   #if defined(PDEF_H)

    INT(N,3,     EJ("Number of random value","出力する乱数の数"))
    REAL(MAX,307,EJ("Max value",             "出力する乱数の最大値"))
    RVEC(X,307,N,EJ("Where to store numbers","乱数の格納場所"))
    PROC(Gen,    EJ("Generate numbers",      "乱数の生成"))
    AUTO("N MAX")
    AUTO("5 100.0")
    AUTO("Seed")
    AUTO("Gen")
    AUTO("Print X")

   #else

    #include "pocom.h"
    CHECK_FILE_NAME

    void Gen(void) {
        Int i;
        NoList=1; Alloc("X");
        for (i=0;i<N;i++) X[i]=Unif()*MAX;
    }

   #endif

これを実行するとデータファイルを用意しなくても、計算を実行できます。

計算ルーチンで、NoList という Int 変数を1に設定しています。 普段は、ポコムではファイルを指定せずにプログラムを起動すると変数のリストを表示します。 NoList を0以外に設定すると、変数のリストを表示する動作を抑止できます。

2.6 メインルーチンを自分で書く場合

以下に例を示します。これはこの章の最初のプログラムと全く同じ動作をします。

   /* Example4.c */
   #define FILE_NAME "Example4.c"

   #if defined(PDEF_H)

    INT(N,3,       EJ("Size of matrix",       "行列の大きさ"    ))
    RMAT(A,307,N,N,EJ("Coefficient matrix",   "係数行列"        ))
    RVEC(B,307,N,  EJ("Right side vector",    "右辺"            ))
    RMAT(C,307,N,N,EJ("Work matrix",          "作業用の行列"    ))
    RVEC(X,307,N,  EJ("Solution vector",      "計算結果"        ))
    PROC(Solve,    EJ("Solve linear equation","連立方程式を解く"))

   #else

    #define CUSTOM_MAIN 1
    #include "pocom.h"
    CHECK_FILE_NAME

    void Solve(void) {
        Int i,j,k;
        Check("A B"); Alloc("C X");
        for (i=0;i<N;i++) for (j=0;j<N;j++) C[i][j]=A[i][j];
        for (i=0;i<N;i++) X[i]=B[i];
        for (k=0;k<N;k++) {
            if (C[k][k]==0) Error("Solve", EJ("Denominator is 0","分母が0"));
            for (j=k+1;j<N;j++) C[k][j]/=C[k][k];
            X[k]/=C[k][k];
            for (i=0;i<N;i++) if (i!=k) {
                for (j=k+1;j<N;j++) C[i][j]-=C[i][k]*C[k][j];
                X[i]-=C[i][k]*X[k];
            }
        }
    }

    int main(int argc,char**argv) {
        InitPocom();
        LoadFiles(argc,argv);
        ExitPocom();
        return 0;
    }

   #endif

第3章 コンパイル方法と起動方法

前の章で作った Example.c をコンパイルすることで、ポコムのプログラムは完成します。

Linux の場合

Linux の場合ならば

    $ gcc -O4 -Wall -DJPN Example.c -lrt -lm

のようにします。すると a.out という名の ポコム コマンドを作ることができます。 ( -DJPN は pocom.h が報告するエラーメッセージを日本語にします。)

Windows でコマンドプロンプトから直接コンパイルする方法

※pocom.zip を展開したら $DoFirst.bat をまず実行します。
次に、コマンドプロンプトを起動します。
そして、例えば、Borland C++ 5.5.1 がインストールされているならば
    C:\...\Pocom\Example>bcc32 -DJPN Example.c

のようにコンパイルとリンクをすれば、 Example.exe という名の ポコム コマンドを作ることができます。

実行の方法

こうして作った a.out または、Example.exe の起動形式はつぎのようになります。
    ./a.out [<ファイル名>]  [<ファイル名>] ...
    Example [<ファイル名>]  [<ファイル名>] ...

起動時にファイルを全く指定しないと、変数のコメントを表示します。 ファイルを指定した場合、左から順番に読み込まれ処理されます。
    $ ./a.out test.txt
    C:\...\Pocom\Example>Example test.txt

データファイルのアイコンを Example.exe のアイコンにドラッグしても、 プログラムを実行することもできます。引数のファイル名に "-" を指定すると、 標準入力から読み込みます。

Windows でバッチファイルからコンパイルする方法

Borland C++ 5.5.1 がインストールされているならば mk.bat というバッチファイルをダブルクリックするだけで Example.exe を作成できます。

他のコンパイラの場合は、フォルダにある $CmdSJIS というショートカットをダブルクリックしてコマンドプロンプトを起動します。
そして Visual C++ 2017 の場合は
    C:\...\Pocom\Example>mk 2017

とします。そして、続けてコンパイラオプションも指定することもできます。
    C:\...\Pocom\Example>mk 2017 /O2 /GL

とします。Mk.bat を複製するなどして、それを編集すると便利です。Mk.bat の中身は
@echo off
if exist Mk.pif del Mk.pif
set COMPILER=Bcc
set PG=Example
set OPTIONS=
set LIBS=
set BIT=64
set JPN=1
set HIT_ENTER=1
if not "%1" == "" set COMPILER=%1
if exist ..\tools\Mk%COMPILER%cc.bat goto CompilerOK
if exist ..\tools\Mk20%COMPILER%.bat goto CompilerOK
if exist ..\tools\Mk%COMPILER%.bat goto CompilerOK
 echo ..\tools\Mk%COMPILER%.bat がありません。
 pause
 goto EndOfBat
:CompilerOK
if exist ..\tools\Mk%COMPILER%cc.bat %COMSPEC% /c ..\tools\Mk%COMPILER%cc.bat %OPTIONS% %2 %3 %4 %5 %6 %7 %8 %9
if exist ..\tools\Mk20%COMPILER%.bat %COMSPEC% /c ..\tools\Mk20%COMPILER%.bat %OPTIONS% %2 %3 %4 %5 %6 %7 %8 %9
if exist ..\tools\Mk%COMPILER%.bat %COMSPEC% /c ..\tools\Mk%COMPILER%.bat %OPTIONS% %2 %3 %4 %5 %6 %7 %8 %9
:EndOfBat

となっており、これを編集すればデフォルトのコンパイラ(COMPILER)やソースファイル(PG)や オプション(OPTIONS)や追加のライブラリ(LIBS)の設定を変えて対応できます。
例えば、同じフォルダの中に Test.c というファイルがあって、 それをコンパイルしたい場合は、set PG=Example という行を set PG=Test と書き換えます。
mk.bat で指定できるコンパイラの一覧は以下の通りです。
50 Visual C++ 5.0
60 Visual C++ 6.0
200202Visual C++ 2002
200303Visual C++ 2003
200505Visual C++ 2005
200808Visual C++ 2008
201010Visual C++ 2010
201313Visual C++ 2013
201717Visual C++ 2017
Bcc B Borland C++ 5.5.1
Gcc G TDM-GCC-64
Lcc L Lsic86
Tcc T TurboC

Lsic86 と TurboC を64ビット Windows で使う場合は「TAKEDA, toshiya's HOME PAGE」の 「MS-DOS Player for Win32-x64」から msdos.exe をダウンロードして Pocom\tools に置く必要があります。
http://takeda-toshiya.my.coocan.jp/
msdos.zip → msdos → binary → i86_x86 → msdos.exe が高速です。
また、Lsic86 や TurboC の本体も C:\app16 というフォルダを作成して、そこに置く必要があります。
Lsic86 は http://www.lsi-j.co.jp/freesoft/
にあります。 Lsic86 の場合は C:\app16\lsic86\bin\_LCC を編集して
# LSI C-86 compiler's configuration file

-DLSI_C
-h
-X\APP16\LSIC86\BIN -L\APP16\LSIC86\LIB -I\APP16\LSIC86\INCLUDE -T -O
-acdos.obj $LSICOPTS
&		#Command line argument will be inserted here
-lknjlib -ldoslib -v

のようにします。
TurboC の場合は C:\app16\tcc\TURBOC.CFG を編集して
-I\APP16\tcc
-L\APP16\tcc

のようにします。

Windows でUTF8モードでコンパイルする方法(Windows7 以降推奨)

Ubuntu はUTF8で作られているので、これから述べる Windows のような面倒な手続き無しでユニコード文字を処理することができます。
一方、Windows はデータファイルにシフトJIS以外のユニコード文字を含めたい場合にはUTF8モードにする必要があります。
シフトJISで用が足りるならばUTF8モードは使わない方が無難です。
UTF8モードを使う場合は Windows XP 以降の Windows である必要があります。
また、UTF8モードを使用する場合は事前に nkf.exe をダウンロードするなどして Pocom\tools フォルダに置く必要があります。
http://hp.vector.co.jp/authors/VA007219/
をスクロールさせて、「nkfwin.zip version 2.1.1 download」をクリックします。
nkf.exe を置いたら、Example フォルダにある SetUTF8.bat をダブルクリックするとUTF8モードになります。
すると Example フォルダにある全てのテキストファイル(*.txt)がUTF8に変換され、 $CmdSJIS というショートカットが $CmdUTF8 に変化します。
元のシフトJISモードに戻すには SetSJIS.bat をダブルクリックします。
SetUTF8.bat 2回連続して実行したり、SetSJIS.bat を2回連続して実行しても問題はありません。
$CmdUTF8 をダブルクリックして開いたコマンドプロンプトでは、起動時に chcp 65001 が実行され、UTF8文字を文字化けすることなく表示できます。
UTF8モードの状態で mk.bat でコンパイルすると、UTF8に対応した Example.exe が作成されます。
mk.bat は現在UTF8モードかどうかを、$CmdUTF8 が存在するかどうかで判断してコンパイルします。
(※コンパイラによっては JPN オプションが無効にされ、日本語をプログラムの中に埋め込むのが不可能な場合があります。
その場合でも、データファイルの日本語のUTF8文字は正しく処理されます。)
そうしてコンパイルできた Example.exe の実行は、
    C:\...\Pocom\Example>Example test.txt

のようにします。
Windows XP や Windows Vista で $CmdUTF8 でコマンドプロンプトを使用する場合は以下の制限があります。 一方、Windows 7 以降ならば
    C:\...\Pocom\Example>mk

のようにバッチファイルをコマンドラインでタイプして実行することができます。
また、3バイトUTF8文字(基本多言語面文字)の桁位置がずれることもありません。
しかし、Windows7 や Windows 8.1 の場合でも画面がスクロールすると表示が乱れる場合があります。
さらに残念なことに、Windows 10 でも4バイトUTF8文字(サロゲートペア文字)や ひらがなカタカナ濁半濁点結合文字やIVS異体字セレクター付き文字は表示桁位置がずれます。
UTF8モードで作成したCSVファイルを正しく表示するにはエクセルは2007以降が必要です。

第4章 データの種類

ポコムは、17種類のデータ型を持っています。

単純変数 INT、INTF、FIXCODEREALSTR
ベクトル(vector) IVECCVECRVECSVECCDEF
固定列行列(matrix) IMATCMATRMATSMAT
可変列行列(jagged) IJAGCJAGRJAGSJAG

空白 # ; $ を含む文字列やコードの名前を指定する時は、 " か ' で囲みます。 また、変数名/関数名と一致する文字列やコード定義を指定する時も " か ' で囲みます。

整数を 0x または 0X で始めると16進数と見なします。 新しいポコムでは 0 から始めても10進数と見なします。 以前のバージョンのポコムのように8進数と見なしたい場合は、 #include "pocom.h" の前に #define ENABLE_OCTAL とします。

コード型については、次の章で詳しく説明します。

ベクトルの大きさは整数変数で制御されます。

固定列行列の大きさは、2つの整数変数で制御されます。 行数は0にできますが、列数は0にできません。 例外として行数が0の時は列数も0になります。 ただし、pocom.h を定義するまえに、#define ALLOW_MAT_0 を定義すれば、 行数が1以上でも列数を0にできます。 ただし、この場合、データの読み込みの時にエラーが起きた場合に、エラーメッセージが不親切になります。

可変列行列は整数と整数ベクトルで行数と各行の長さが決ります。 行数も列数も0にできます。

第5章 コード型の使い方

整数演算と、文字列演算の性能を比較すると、 整数演算の方が速度・メモリ効率ともに優れています。 だからといって、プログラムやデータを整数で記述すると、 読みやすさをそこないます。 速度・メモリ効率と読みやすさを両立するために、C 言語では

    enum { SUN, MON, TUE, WED, THR, FRI, SAT };
    int DayMat[N][N] = { { SUN, MON, TUE },
                         { MON, TUE, WED },
                         { TUE, WED, THR } };

とするテクニックがよく使われます。 上の例は曜日型の行列の宣言もしています。 これは、曜日しか要素に持たない N×N 行列を表します。 計算機の内部では、SUN や MON といった文字列は使われずに、 0や1が配列に格納されます。 したがって、速度・メモリ効率とプログラムの読みやすさを両立します。

C 言語の enum、#define では、文字列 SUN、MON 等は、 コンパイラがプログラムを解釈するときだけ使われます。 コンパイルで得られたコマンドの入力や出力では、 SUN や MON を利用することはできません。 したがって、プログラムを読みやすくすることはできても、 データを読みやすくするには、 自分で読み込みプログラムと出力プログラムを書かなければなりません。

ポコムのコード型 (code、cvec、cmat、cjag) を使うと、 速度とデータの読みやすさを両立することができます。 たとえば、上の曜日型の行列を ポコムのコード型で実現するには

    FIX(7)
    CDEF(DayOfWeek,9,FIX7,      EJ("Day of week definition","曜日のコード定義"))
    INT(N,2,                    EJ("Size of matrix",        "行列の大きさ"))
    CMAT(DayMat,3,N,N,DayOfWeek,EJ("Day of week matrix",    "曜日の行列"))
    AUTO("DayOfWeek")
    AUTO("SUN MON TUE WED THR FRI SAT $")

を書いておきます。 こうすれば、データ ファイル上での曜日型の行列の入出力は

    DayMat
    SUN MON TUE ;
    MON TUE WED ;
    TUE WED THR $

の形式になります。 この時、SUN から SAT には0から順に番号がふられます。 行列 DayMat にはふられた番号が格納されます。 N には3が設定されます。 この行列を Print 関数を使わずに、直接表示するプログラムは以下のようになります。

    for (i=0;i<N;i++) {
        for (j=0;j<N;j++)
            fprintf(fp," %s",DayOfWeek[ DayMat[i][j] ]);
        fprintf(fp,"\n");
    }

コードの名前には、数字・日本語等も登録できます。 ただし、1つのコード定義に、同じ名前を複数登録することはできません。

第6章 データ ファイルの形式

ポコムには、以下に示す4種類の行があります。

注釈行
注釈行は # で始まります。注釈行は無視されます。
関数行
関数名が先頭に来て、後にパラメータが続く行です。
変数行
データを読み込む順番を決める行です。 # より右は読み込みません。
データ行
変数行で指定した順番にならんだデータの集まりです。 # より右は読み込みません。 ; で行列の行末を決めます。 固定列行列を複数並べた時は、 それぞれの行末に ; を付ける必要がありますが、 可変列行列を複数並べた場合は、1つだけ ; を付けます。 $ は配列の終わりを決めます。$ より右は読み込みません。

変数行を書く時は、次の順番を守って変数を並べなければなりません。

      [単純変数]  [ベクトル・固定列行列]  [可変列行列]

さらに、ベクトル、固定列行列、可変列行列を複数並べる時は、 行サイズを指定する整数変数が同じものでなければなりません。 また、可変列行列を複数並べる時は、 列サイズを示す整数ベクトル変数も同じものでなければなりません。

変数行の後には、それに応じた量のデータが必要になります。 この行をデータ行と呼びます。 データ行での読み込みの順番は、変数行での順序から次のように決ります。

順番さえあっていれば、改行や注釈は自由に配置できます。 したがって、工夫次第で、読みやすく、 かつページ数が少ないデータ ファイルを書くことができます。

第7章 データ ファイルの例

次のデータは、ベクトルと固定列行列を表現します。 N は Int、X は rvec[N]、A、C は rmat[N,N] です。

     A             C             X     # これが変数行
     1.2 6.6 2.2 ; 2.3 4.4 5.5 ; 3.0   #  *------------------*
     4.3 6.4 0.4 ; 5.3 2.3 6.4 ; 2.0   #  | これらがデータ行 |
     3.2 0.5 7.2 ; 2.3 3.4 2.7 ; 1.0 $ #  *------------------*

次のデータは、可変列行列の例を示しています。 N は Int、Lenは ivec[N]、X は rvec[N]、U、V は rjag[Len] です。 最初に U に下三角行列を入力する例を示します。

     U
      1.2 ;       # Len には(1、2、3)が設定されます。
      4.3   6.4 ;
      3.2   0.5   7.2 $

次に、X、U、V を同時に入力する例を示します。 上の A、C との順序の違いに注意してください。

     X   U   V 
     3.0 1.2 2.3 ;
     2.0 4.3 5.3
         6.4 2.3 ;
     1.0 3.2 2.3
         0.5 3.4
         7.2 2.7 $

ポコムは、ネットワークを表現するのに適しています。 例えば有向グラフは、2つの cvec による枝集合でも、 svec による隣接行列でも、表現できます。 下に例として、ノード数4のサーキットの場合を示します。

    #    [N1] → [N2]
    #     ↑      ↓
    #    [N4] ← [N3]

    Node                  #  N    : Int     ノードの数
    [N1] [N2] [N3] [N4] $ #  Node : cdef[N] コード定義

    From To               # cvec、 From と To によるサーキット
    [N1] [N2]             #
    [N2] [N3]             #  E    : Int           枝の数
    [N3] [N4]             #  From : cvec[E]<Node> 枝の出発点を表す
    [N4] [N1] $           #  To   : cvec[E]<Node> 枝の到達点を表す

    Adj                   #  svec による隣接行列
    -*--                  #
    --*-                  #  Adj  : svec[N]  隣接行列
    ---*                  #  [i][j]に * があれば i から j への枝
    *--- $                #  があることになる。Format は0にする。
                          #  そうしないと改行されない  
                          # N と E には自動的に 4 が設定される

第8章 文字列変数の扱い

まれに、計算ルーチンで STR、SVEC、SMAT、SJAG 変数に 文字列を割り当てる必要がでできます。 この場合は、StrDup( ) を使います。

(以前のバージョンでは効率が悪かったので StrDup( ) の仕様を変更しました。 元のルールで StrDup( ) や GetMem( ) を使って文字列を処理していたソースを 使う場合は、pocom.h をインクルードする前に #define NO_FAST_STR を定義してください。)

例題としてデータ定義が以下の場合を考えます。

    STR(S,10,    EJ("String variable","文字列変数"))
    INT(N,2,     EJ("Size",           "大きさ"))
    SVEC(SV,10,N,EJ("String vector",  "文字列ベクトル"))

以前のバージョンでは以下の例はエラーでしたが、現在はエラーとなりません。

    FreeMem(S); S="abc";
    N=4; Alloc("SV"); 
	SV[1]="abc"

新しいポコムで、文字列を動的に確保する場合は以下のようにします。

    S=StrDup("abc",S);
    SV[2]=StrDup("abc",SV);
    SV[3]=GetMemStr(11,SV);
	memset(SV[3],'-',10);

古いポコム、または、NO_FAST_STR が有効なときは以下のようにします。

    S=StrDup("abc");
    SV[2]=StrDup("abc");
    SV[3]=GetMem(11,1);
	memset(SV[3],'-',10);

FreeMem(S); Alloc("SV"); は、まとめて Alloc("SV S"); と書いても構いません。

第9章 データ定義マクロ リファレンス

データ定義では、マクロで変数・関数・初期化データを指定します。 以下にこれらのマクロの書式を示します。

PROC(n,m) 引数を持たない関数
FUNC(n,m) 引数を持った関数
INT(n,w,m) 整数
INTF(n,w,f,m) 固定値整数
FIX(f) 固定値整数(簡略表現)(非負)
CODE(n,w,d,m) コード
REAL(n,w,m) 浮動小数点
STR(n,w,m) 文字列
IVEC(n,w,r,m) 整数ベクトル
CVEC(n,w,r,d,m) コード ベクトル
RVEC(n,w,r,m) 浮動小数点ベクトル
SVEC(n,w,r,m) 文字列ベクトル
CDEF(n,w,r,m) コード定義
IMAT(n,w,r,c,m) 整数固定列行列
CMAT(n,w,r,c,d,m)コード固定列行列
RMAT(n,w,r,c,m) 浮動小数点固定列行列
SMAT(n,w,r,c,m) 文字列固定列行列
IJAG(n,w,s,m) 整数可変列行列
CJAG(n,w,s,d,m) コード可変列行列
RJAG(n,w,s,m) 浮動小数点可変列行列
SJAG(n,w,s,m) 文字列可変列行列
AUTO(t) 起動時に自動実行するデータを書く

記号説明
nC 言語上での変数名・関数名 N または、Solve
w表示する時の桁数 10 または、-310
f固定値整数値 3など(0x から始めると16進数)
r行の数 N
c列の数 N
s大きさを決める ivecLen
dコード定義 cdef Node
mコメント "行列の大きさ"
tデータ "Range N > 0"

n は C の識別子として許され、かつ _ で終わってはなりません。 w は、データを表示する時の桁数を決めています。 詳しくは第10章の Format を参照してください。

第10章 ポコム関数、標準関数、標準変数リファレンス

ポコム関数は、データ ファイルからでも、AUTO からでも、 計算ルーチン等の C の関数からでも呼び出すことができます。

ポコム関数は C の関数として呼び出す時は、文字列を引数とします。

Alias変数/関数に別名をつける。日本語も指定できる。 主に AUTO マクロ内で使用される。
         例   Alias N 数 A 係数行列 B 右辺 C 作業用 X 解 Solve 実行
    
Append以降の出力を指定されたファイルへ追加書き込みする。- を指定すると標準出力へ書く。 + を指定すると標準エラーへ書く。
Clock起動した時からの経過時間を表示する。引数をコメントとして表示する。
Echo文字列の表示。# よりも後ろの文字列も出力される。
Format変数の出力桁数を変更する。 出力の精度を高くしたり、 画面にたくさんのデータを表示したりするときに使用する。 下2桁が全体の桁数を表し、百の桁が小数点以下の桁数を示す。 浮動小数点で -209 のように負の符号を付けると、3.14e+000 の形式で出力する。 整数で -4 のように負の符号を付けると16進数で出力する。 浮動小数点で0または -1 に指定した時は、必要に応じた精度で表示する。 浮動小数点で -2 または -3 に指定した時は、16進数で表示する。 固定列行列以外の配列で、0に指定した場合は、 単独で表示したときでも要素ごとに改行される。 また、RVEC、RJAG で、-2 に指定した場合も、 単独で表示したときでも要素ごとに改行される。 同時に複数の変数の桁数を変えることができる。
         例  Format  A 408   B 408   X 408
    
Free変数のメモリを開放して初期化する。Free を使うとサイズの変数を変えずに、 メモリを開放して、ポインタを0にできる。
Lap最初に呼び出された場合は Clock と同じように起動時からの経過時間を表示する。 2回目以降は前回の Lap の呼び出しからの経過時間を表示する。 引数をコメントとして表示する。
LimitPrint するときに、一番右の配列を並べて表示する数を制限して折り返す。
@一番右の配列がベクトルならば、左には単純変数のみを指定できる。
A一番右の配列が固定列行列・可変列行列ならば、左には単純変数とベクトルを指定できる。
大きな配列を長さ80文字以内の行に収めたい場合などに使う。 Limit 0 とすると解除される。
List変数と関数の一覧を表示する。引数は取らない。 標準変数 NoList が0以外の場合でも表示する。
Load指定されたファイルを読む。- を指定すると標準入力を読む。
Output以降の出力を指定されたファイルへ書く。 同じ名前のファイルがあるときは上書きされる。 - を指定すると標準出力へ書く。+ を指定すると標準エラーへ書く。
Print変数の表示。複数の変数を同時に指定する時は、 読み込みと同様変数の順番とサイズが合ってなければならない。
変数名に続けて ; と任意の文字列を指定することによって、 出力される変数名を一時的にその文字列に変更することが可能。
PrintCSVCSVフォーマットに従って変数の値を表示する。 エクセルで読み込むのに使用する。" や ' を含む文字列型を書きだすと列が乱れる。
変数名に続けて ; と任意の文字列を指定することによって、 出力される変数名を一時的にその文字列に変更することが可能。
Range 整数、浮動小数点、コード型変数の取る値を制限する。 主に AUTO マクロ内で使用される。 範囲条件の種類として ==、!=、>、>=、<、<= が使える。
    例  Range N >= 0  # N は 0 以上に制限される。
   
また、複数の範囲条件を設定することができる。
    例  Range N > 0 <= 10 != 5
   
この場合 N は 1,2,3,4,6,7,8,9,10 に制限される。 (注意! 範囲条件を表す記号の前後に必ず空白を置くこと。)
Pocom Version 3 より前は何度も解除/設定できたが、 Version 3 以降は一つの変数に対して1回だけしか設定できなくなった。 理由は AUTO マクロで暴走しないように Range を設定したのに、データファイルで Range を変更することにより、 暴走するデータが作れることを防ぐため。
Seed乱数の種を設定する。 これにより、標準関数 Unif( ) の返す乱数系列を違うものに変更できる。 引数がない場合は、現在時刻を種とする。 Seed を呼び出さずに Unif( ) を呼び出すと Seed("1") の状態から実行される。

標準変数・定数・型は計算ルーチン等 C の関数から参照できます。

ALWAYS_FALSE常に偽。条件分岐に使っても警告が出ない。
EJ(E,J)マクロ JPN が1なら日本語、0なら英語に切り替えるマクロ
例:fprintf(fp,EJ("English","日本語 "));
bool EndOfLineバッファの終わりまで読んだら true。
double EXA#define EXA (1048576.0*1048576.0*1048576.0)
乱数をジャンプさせるときに便利。
ただし、Jump(EXA+1.0) のように指定しても 1.0 は丸められて Jump(EXA) と結果は変わらない。何故なら、 多くの場合 double は53ビットの仮数部を持つのに対し EXA は60ビットだからである。
FILE*fp出力ファイル。通常は stdout に設定されている。Append、Output で変更する。
Int通常の場合 int で、 #include "pocom.h" の前に #define INT_64 とすると long long または __int64。
16ビットコンパイラで、 #include "pocom.h" の前に #define INT_32 とすると long。
Int32_t32ビット符号付整数。
Int64_t64ビット符号付整数。
size_t Limit__Print するときに、一番右の配列を並べて表示する数を制限して折り返す。
@一番右の配列がベクトルならば、左には単純変数のみを指定できる。
A一番右の配列が固定列行列・可変列行列ならば、左には単純変数とベクトルを指定できる。
大きな配列を長さ80文字以内の行に収めたい場合などに使う。 Limit__=0; とすると解除される。
MODEL_SIZE(A,B,C,D)メモリモデル別に値を選ぶ
16ビット:スモールモデル・ミディアムモデル:A
16ビット:ラージモデル・コンパクトモデル:B
32ビット:C
64ビット:D */
#define MODEL_SIZE(A,B,C,D) (sizeof(int)<=2?(sizeof(int*)<=2?A:B):sizeof(int)<=4?C:D)
Int NoList0以外に設定すると変数のリストを表示する動作を抑止する。
double PETA#define PETA (1024.0*1048576.0*1048576.0)
乱数をジャンプさせるときに便利。
EXA と違い50ビットなので Jump(PETA+1.0) としても正しくジャンプする。
PRI3232・64ビットコンパイラなら "" 16ビットコンパイラなら "l"。
fprintf(fp,"# %" PRI32 "d\n",(Int32_t)x); のように使う。
PRI64"ll" または "I64"。
fprintf(fp,"# %" PRI64 "d\n",(Int64_t)x); のように使う。
PRIzInt が int なら ""。
Int が long long または __int64 なら "ll" または "I64"。
16ビットコンパイラで Int が long なら "l"。
fprintf(fp,"# %" PRIz "d\n",(Int)x); のように使う。
Rand_t乱数のワークエリアを確保するとき宣言する。
   Rand_t LocalSeq;  /* ローカルに乱数の状態を確保 */
   Srand_r(1,LocalSeq); /* 1を種に領域の初期化 */

   /* スレッドの番号を利用して、他のスレッドから十分に離れた場所へジャンプ */
   Jump_r(PETA*ThreadNo,LocalSeq);
   
のように使う。
real通常の場合 double で、 #include "pocom.h" の前に #define FLOAT_REAL とすると float。
FILE*Stderrエラー出力ファイル。通常は stderr が設定されている。
Uint32_t32ビット符号なし整数。
Uint64_t64ビット符号なし整数。
Unsigned通常の場合 unsigned で、 #include "pocom.h" の前に #define INT_64 とすると unsigned long long または unsigned __int64。
16ビットコンパイラで、 #include "pocom.h" の前に #define INT_32 とすると unsigned long。
vmj高速線形リストの型。vec,mat,jag の頭文字が名前の由来。
typedef union  dataunion {
  Int i; real r; str s; void*v; int ii[2]; str ss[2]; void*vv[2]; headrec h;
  VMJ_USER
} dataunion;
typedef struct vmj { dataunion data; struct vmj*next;      } vmj;
のように宣言されており、vmj*v=GetVmj(); ... FreeVmj(v); のように確保と開放を行う。
wptr制御構造体の共用体へのポインタ
char ZeroStr[1]長さ0の文字列定数

標準関数は計算ルーチン等 C の関数から呼び出します。

void Alloc(char*)配列の確保を行う。例 Alloc("C X") ;
void AllocWord(VAR)配列の確保を行う。例 AllocWord( C ) ;
void AllocWord__(wptr)配列の確保を行う。例 AllocWord__((wptr)C_ ) ;
Uint32_t BackRand()整数乱数を逆順に生成する。 pocom.h をインクルードする前に BACK_RAND を0以外に定義すると使用可能。
Uint32_t BackRand_r(Rand_t)整数乱数を逆順に生成する。マルチスレッド用。 pocom.h をインクルードする前に BACK_RAND を0以外に定義すると使用可能。
double BackUnif()浮動小数点乱数を逆順に生成する。 pocom.h をインクルードする前に BACK_RAND を0以外に定義すると使用可能。
double BackUnif_r(Rand_t)浮動小数点乱数を逆順に生成する。マルチスレッド用。 pocom.h をインクルードする前に BACK_RAND を0以外に定義すると使用可能。
void Check(char*)配列のエラーチェックを行う。例 Check("A B") ;
bool CheckIntOverflow(n,mul,add)n*mul+add の結果がオーバーフローしたら1を返す。
n、add は Int 型。mul は1以上の Int 型。以下のように定義されている。
#define CheckIntOverflow(n,mul,add) \
((mul)<=0||(n)>((((Unsigned)1)<<(sizeof(Int)*8-1))-1-(add))/(mul))
void CheckWord(VAR)配列のエラーチェックを行う。例 CheckWord( A ) ;
void CheckWord__(wptr)配列のエラーチェックを行う。例 CheckWord__((wptr)A_ ) ;
double ClockSec()プログラム開始からの経過時間を秒単位で返す。
void CopyArg(char*,char*)引数をバッファに転送する。 第一引数は親関数名、第二引数は転送する文字列。
例 CopyArg("foo",argument) ;
void EndArg()引数の処理が終わったことをシステムに知らせる。
void Error(char*,char*)エラーメッセージを表示して終了する。
void FreeMem(void*)free( ) または、delete[ ] の代わりに使う。
void FreeVmj(vmj*)高速線形リストを一つ開放する
void FreeWord(VAR)メモリの開放を行う。例 FreeWord( A ) ;
void FreeWord__(wptr)メモリの開放を行う。例 FreeWord__((wptr)A_ ) ;
char*GetMem(Int,Int)calloc( ) または、new[ ] の代わりに使う。領域は0で埋められる。 CHECK_MEM が0以外に定義されていると、マルチスレッドに対応しなくなる。
char*GetMemStr(size_t,SVAR)文字列変数にメモリを確保する。
SV[1]=GetMemStr(80,SV);
のように使う。領域は0で埋められる。
ALIGN_MEM の影響を受けずにメモリをパックする。
vmj*GetVmj()高速線形リストを一つ確保する
void Jump(double)乱数をジャンプさせる。 pocom.h をインクルードする前に JUMP_RAND を0以外に定義すると使用可能。 BACK_RAND を0以外に定義すると負の値で逆方向へジャンプできる。
void Jump_r(double,Rand_t)乱数をジャンプさせる。マルチスレッド用。 pocom.h をインクルードする前に JUMP_RAND を0以外に定義すると使用可能。 BACK_RAND を0以外に定義すると負の値で逆方向へジャンプできる。
double LapSec()直前の Lap 関数の呼び出しからの経過時間を秒単位で返す。
Uint32_t Rand()32ビットの符号なし整数乱数を返す。
Uint32_t Rand_f()0以外の32ビットの符号なし整数乱数を返す(高速低品質)。
Uint32_t Rand_m(N)0以外の32ビットの符号なし整数乱数を返す(高速低品質)。マルチスレッド用。N は0以上 FAST_RAND 未満。
Uint32_t Rand_r(Rand_t)マルチスレッド用の32ビットの符号なし整数乱数。
code ReadCode(CDEF)バッファからコードを読む。(範囲チェックなし)
例 i = ReadCode( Node ) ;
code ReadCodeRange(CDEF,CVAR)バッファからコードを読む。 (範囲チェックを行う。CVAR は CODE,CVEC,CMAT,CJAG のいずれか)
例 i = ReadCodeRange( Node,From ) ;
Int ReadInt()バッファから整数を読む。(範囲チェックなし)
Int ReadIntRange(IVAR)バッファから整数を読む。 (範囲チェックを行う。IVAR は INT,INTF,FIX,IVEC,IMAT,IJAG のいずれか)
例 i = ReadIntRange( N ) ;
real ReadReal()バッファから浮動小数点を読む。(範囲チェックなし)
real ReadRealRange(RVAR)バッファから浮動小数点を読む。 (範囲チェックを行う。RVAR は REAL,RVEC,RMAT,RJAG のいずれか)
例 r = ReadRealRange( A ) ;
char*ReadStr()バッファから文字列を読む。
wptr ReadWord()バッファから変数名・関数名を読む。
void SizeChangedBy(SIZE,BY)SIZE:INTまたはIVEC、BY:変数または関数。SIZEを変化させた原因を記録する。
void Srand(Uint32_t)乱数初期化。第一引数に種を指定する。
void Srand_r(Uint32_t,Rand_t)マルチスレッド用の乱数初期化。第一引数に種を指定する。
char*StrDup(char*,SVAR)strdup( ) の代わりに使う。目的は文字列変数の修正など。
例:SV[1]=StrDup("abc",SV);
void SwapRow(mat,Int,Int)行列の二つの列やベクトルの要素を入れ替える。可変列行列には使用しないこと。
double Unif()0以上1未満の浮動小数点乱数を返す。
double Unif_f()0より大きく1未満の浮動小数点数乱数を返す(高速低品質)。
double Unif_m(N)0より大きく1未満の浮動小数点数乱数を返す(高速低品質)。マルチスレッド用。N は0以上 FAST_RAND 未満。
double Unif_r(Rand_t)マルチスレッド用の0以上1未満の浮動小数点乱数。

第11章 X86_INTRIN について

pocom.h をインクルードする前に #define X86_INTRIN のように定義すれば、 以下の関数が使用可能になります。

これらはコンパイラやアセンブラを使わず、機械語をプログラムに埋め込んだので、 Borland C++ 5.5.1 でも使用可能です。もちろん16ビットコンパイラやインテルや AMDのCPU上以外では使うことはできません。

void RetOnly( )何もしない。すぐに返る。
関数呼び出しのオーバーヘッドを計測するため。
int HaveCpuid( )Cpuid が使用可能なら1
int HaveSSE( )SSE が使用可能なら1
int HaveSSE2( )SSE2 が使用可能なら1
int HaveSSE3( )SSE3 が使用可能なら1
int HaveSSSE3( )SSSE3 が使用可能なら1
int HaveSSE4_1( )SSE4.1 が使用可能なら1
int HaveSSE4_2( )SSE4.2 が使用可能なら1
int HaveAVX( )AVX が使用可能なら1
int HaveAVX2( )AVX2 が使用可能なら1
int HaveRdtsc( )Rdtsc( ) が使用可能なら1
int HaveRdtscp( )Rdtscp(Uint32_t*aux) が使用可能なら1。
( core i7,i5,i3 等のCPUで使用可能 )
int HaveRdrand( )物理乱数 Rdrand32( ) と Rdrand64( ) が使用可能なら1。
第3世代の Core i7,i5,i3 以降のCPU等で使用可能
Int64_t Rdtsc( )CPUの rdtsc 命令を使って現在のクロックカウンターを得る
Int64_t CpuidRdtsc( )CPUの cpuid 命令を実行した後 rdtsc 命令を使って現在のクロックカウンターを得る。
Rdtsc( ) より時間がかかるが、より正確に計測することができる。
Int64_t Rdtscp(Uint32_t*aux)CPUの rdtscp 命令を使って現在のクロックカウンターを得る。
aux で示された場所に IA32_TSC_AUX MSR(使用しているプロセッサの番号) を保存する。aux を0にすると保存しない。
工夫すれば Rdtscp(unsigned*aux) のほうが CpuidRdtsc( ) よりもさらに正確なクロック数を得ることができる。
int Bsf32(Uint32_t)Bit scan forward を行う。0の結果は未定義。
int Bsf64(Uint64_t)Bit scan forward を行う。64ビットのプログラムのみ使用可能。0の結果は未定義。
int Bsr32(Uint32_t)Bit scan reverse を行う。0の結果は未定義。
int Bsr64(Uint64_t)Bit scan reverse を行う。64ビットのプログラムのみ使用可能。0の結果は未定義。
int Bswap32(Uint32_t)バイトの順番を並び替える。
int Bswap64(Uint64_t)バイトの順番を並び替える。64ビットのプログラムのみ使用可能。0の結果は未定義。
int Rdrand32(Uint32_t*val)CPUの rdrand 命令を使って32ビットの物理乱数を val で示された場所に得る。
失敗すると0が返り、成功すると1が返る。
int Rdrand64(Uint64_t*val) Rdrand32( ) の64ビット版

第12章 諸注意