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

目次

第1章 ポコムとは

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

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

pocom.html  このファイル
pocom.h     ポコムのシステムを記述した C 言語ファイル
Example1.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:\>Example1 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 は自動的に設定されます。 ポコムでは入力ファイルと出力ファイルの形式は同じです。

ポコムバージョン5.01から以下のようなCSVファイルも読み込めるようになりました。

test.csv:
A,B
2,5,7,;,23
4,13,20,;,58
8,29,50,;,132

Solve
Print,N,A,X,B

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

/* Example1.c */
#define FILE_NAME "Example1.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];
        }
        Progress("#Solve ",k,N);
    }
 }

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

2.1 データ構造の記述

ポコムは幾つかのデータ型を用意しています。ここではその一部を紹介します。 他のデータ型は第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 は浮動小数点のベクトルを示しています。

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

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 は real**A; のように宣言したことになります。
厳密にはコンパイラによって real*const __restrict*__restrict A; となります。 ただし、#include "../pocom.h" の前に #define NO_RESTRICT とすると、 常に real*const*A; となります。 real は通常 double です。#define FLOAT_REAL とすると real は float になります。 C++コンパイラで #define HALF_REAL とすると real は half になります。
例えば、行列 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行目以降の数字、2 と 307 は、データを表示する時の桁数を決めています。 関数の宣言では指定しません。 この 2 はスペースを含まない最大の桁数を指定しています。 したがって N は -9 から 99 までは桁ずれを起こさずに表示できます。 数字の下位2桁のみが桁数として有効です。 百の桁は、小数点以下の桁数を表すのに使われます。 307 は小数点以下3桁、全体で7桁を使って表示することを意味しています。 この桁数はポコム関数 Format により、 実行時に変更できます。

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

1番右のの"Size of matrix"は、 ファイルを指定せずに起動する時に表示されるコメントを決めています。 "Coefficient matrix"...も同様です。
これを、コメントだけを表示しない場合は空文字列、"" あるいは ZeroStr とします。
0(NULL) にすると、ファイルを指定せずに起動する時に変数の表示の一覧から除外されます。
英語と日本語の両方に対応するには。 以下のように EJ マクロを使います。コンパイル時に JPN マクロが0以外だと、 EJ マクロは日本語のメッセージを有効にし、JPN マクロが定義されていなかったり、 0と定義されていれば英語のメッセージを有効にします。プログラムに日本語を 埋め込む場合はできるだけ EJ マクロを使って日本語が使えないときに備えて下さい。 なお、32/64ビットコンパイラで JPN が無効な時は、 プログラムやデータファイルの文字コードから推測して、 出力桁数を自動調整するようになります。一方、JPN が有効な時は pocom.h の文字コードに 従って出力桁数を調整します。なお、16ビットのコンパイラの場合で WINUTF8 と JPN が無効の場合は、 デフォルトで後で説明する NO_ADJUST が有効になり桁の調整を行いません。 この場合、シフトJISのみ対応となります。 16ビットのコンパイラで他の文字コードで自動桁調整を行いたい場合は pocom.h をインクルードする前に、
#define USE_ADJUST
としてください。

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];
         }
         Progress("#Solve ",k,N);
     }
 }

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

計算ルーチンで定義する変数名や関数名も i_ や i__ のように _ で終わってはいけません。

関数 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"));

関数 Progress( ) は進捗率を 0.5 秒ごとに表示します。この例題のデータは N が 3なので意味がありません。 しかし、N が 5000 や 10000 になると、計算時間は N の3乗に比例するので数分間画面に 全く変化が見られなくなり、暴走しているのかいないのかが分からなくなってしまいます。
また、後で説明するウィンドウズモードの場合は Progress( ) がないと閉じるボタンも反応しなくなります。
この場合プログラムを終了するには、タスクマネージャーを起動して止めるしかありません。

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

空白行や $ の 直前の ; は省略することができます。
省略した形式は古い形式のデータです。 新しい pocom.h は、新しい形式でも古い形式でも読み込むことができます。

また、後で説明するポコム関数 Add と Reset を使用して、以下のように書くことも可能です。

Reset A B
Add B  23.000  A 2.000   5.000   7.000 $
Add B  58.000  A 4.000  13.000  20.000 $
Add B 132.000  A 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)でエラーが発生!

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 以外の値になると Check() でエラーとなるようにできます。 (FIX は以前は INTF と同じでしたが、現在は異なります)

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

さらに、下の test.txt には Print 関数の表示変数名変更機能の例も示します。 これは、.csv ファイルを作成してエクセルに読み込ませる時に、列の名前を日本語化するのに便利です。

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

#if defined(PDEF_H)

 LIST("# " FILE_NAME " version 8.14")
 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,nn=MulAdd(N,N,0);
     Check("A B"); NP1=MulAdd(N,1,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);
         else Progress("#Solve ",K*(2*N-K),nn);
     }
     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   係数行列                  解      右辺
   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

先頭の LIST マクロは有っても無くてもかまいません。 これはパラメータを無しで起動したときや List コマンドを実行した時に表示する変数リストと 一緒に表示するバージョン情報などを加えます。

nn=MulAdd(N,N,0); と NP1=MulAdd(N,1,1) は、それぞれ nn=N*N; NP1=N+1; が整数オーバーフローを起こしている場合に エラーとしてプログラムを終了します。

また、今まで例題では単純化するため Progress("#Solve ",K,N); としていました。 この場合 K が小さい時は進み方が遅く、K が N に近づくと早く進むようになります。
そこで Progress("#Solve ",K*(2*N-K),nn); と変更すると、進捗率の表示が、 ほぼ実行時間に比例して表示されるようになります。

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

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以外に設定すると、変数のリストを表示する動作を抑止できます。

また、ポコムバージョン 7.02 からはファイルを指定せずに起動すると、通常は ファイル選択ダイアログが出現しますが、NoList を0以外にすると、これも抑止できます。

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

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

/* Example4.c */
#define FILE_NAME "Example4.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

 #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","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];
         }
         Progress("#Solve ",k,N);
     }
 }

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

#endif

2.7 LAST マクロでデータのみを渡して計算する

LAST にはプログラムが終了するときに実行するコマンド記述します。 これにより、データファイルに Solve と Print を記述していたのを、 省略することができるようになります。

/* Example1.c */
#define FILE_NAME "Example1.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")
 LAST("Solve")
 LAST("Print N A X B")

#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];
         }
         Progress("#Solve ",k,N);
     }
 }

#endif
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

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

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

Linux の場合

Linux の場合ならば

$ g++ -I. -O4 -Wall -DJPN -o Example1 Example1.c

のようにします。すると Example1 という名の ポコム コマンドを作ることができます。 ポコムの2023年8月のバージョンから gcc/g++ の場合 -I. オプションが必要になりました。 ( -DJPN は pocom.h が報告するエラーメッセージを日本語にします。)

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

pocom.zip を解凍したら、まず最初に $DoFirst.bat を実行してください。 共通ファイルが必要なフォルダにコピーされます。

処理が終わりました

続行するには何かキーを押してください ...
でキーを押す前に端末のウィンドウのタイトルバーを右クリックして、 [プロパティ]を選びます。
[フォント]タブの[フォント(F)]で[MS ゴシック]を選びます。
次に、コマンドプロンプトを起動します。
そして、例えば、Borland C++ 5.5.1 がインストールされているならば
C:\ ... \Pocom\Example>path C:\Borland\bcc55\bin;%PATH%
C:\ ... \Pocom\Example>bcc32 -O2 -DJPN -P Example1.c

のようにコンパイルとリンクをすれば、 Example1.exe という名の ポコム コマンドを作ることができます。
TDM-GCC-64 ならば、
C:\ ... \Pocom\Example>path C:\TDM-GCC-64\bin;%PATH%
C:\ ... \Pocom\Example>g++ -I. -Wall -O4 -o Example1.exe Example1.c
のようにしてコンパイルします。 ポコムの2023年8月のバージョンから gcc/g++ の場合 -I. オプションが必要になりました。

その他のシステム場合

私は Windows と Ubuntu マシンしか所有していないので、確認できませんが、それ以外のマシンでは
64ビットでコンパイルする場合は SYSTEM64 を定義する必要があります。
32ビットでコンパイルする場合は SYSTEM64 を定義する必要はありません。

    $ cc -DJPN -DSYSTEM64 Example1.c -lm

pocom.h 内の SYSTEM64 の定義は以下のようになっています。

#if !defined(SYSTEM64)
 #if defined(_M_X64)||defined(__x86_64__)
  #define SYSTEM64 1
 #elif defined(__SIZEOF_SIZE_T__) && __SIZEOF_SIZE_T__ == 8
  #define SYSTEM64 1
 #else
  #define SYSTEM64 0
 #endif
#endif

これでインテルCPUのコンパイラは SYSTEM64 の自動判別はほとんど上手くいくはずですが、念のため。

また、GNUC 以外のコンパイラでビッグエンディアンのプログラムをコンパイルするには、 BIG_E を定義するしなければならないようになりました。

実行の方法

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

起動時にファイル名を全く指定しないと、変数のコメントを表示します。 ファイルを指定した場合、左から順番に読み込まれ処理されます。
ポコムバージョン 7.02 以降でWindows のコンパイラで作成した場合、 ファイル名を全く指定しないとファイル選択ダイアログが出現して読む込むことができます。 ダイアログをキャンセルすると変数のコメントを表示します。
$ ./Example1 test.txt
C:\ ... \Pocom\Example>Example1 test.txt

データファイルのアイコンを Example1.exe のアイコンにドラッグしても、 プログラムを実行することもできます。引数のファイル名に "-" を指定すると、 標準入力から読み込みます。
-b オプションを指定するとファイルの先頭にUTF8のBOMを書きだします。
-<num> オプションを指定すると32/64ビットコンパイラの場合、 ポコムが実行時に確保するメモリの上限をギガバイト単位で指定できます。
例えば、 -0.0001 とすると 100,000 バイト(100キロバイト)に制限します。
また、-2 とすると2ギガバイトまでメモリを使うことができます。
32ビットコンパイラの既定値は -1 で -0.0001 が最小値で、-4.275 が最大値です。 ウィンドウズの32ビットプログラムでは2ギガバイト前後しか確保できませんが、Ubuntu の 32ビットプログラムは4ギガバイト前後まで確保できます。
64ビットコンパイラの場合の既定値は -5 で -0.0001 が最小値で、-1000.0 が最大値です。 つまり1テラバイトが最大値です。 このオプションの目的はプログラムのミスでメモリを使いすぎてスワップを起こすのを防ぐことです。

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

TDM-GCC-64 がインストールされているならば M.bat というバッチファイルをダブルクリックするだけで Example1.exe を作成できます。

TDM-GCC-64 をインストーラーは以下のリンク先で入手できます。

https://jmeubank.github.io/tdm-gcc/
インストールするときは OpenMp にチェックを入れるのを忘れないで下さい。
m.bat をダブルクリックするとコンソール版のプログラムが作成されます。
mk.bat をダブルクリックするとウィンドウ版のプログラムが作成されます。
コンパイラオプションを指定したい場合は、 フォルダにある $CmdSJIS というショートカットをダブルクリックしてコマンドプロンプトを起動します。
そして、
C:\ ... \Pocom\Example>m -DJPN

とします。
TDM-GCC-64 でC++ではなく、Cとしてコンパイルしたい場合は、
C:\ ... \Pocom\Example>m gccc
または、省略して
C:\ ... \Pocom\Example>m gc

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

とします。

C++ではなく、Cとしてコンパイルしたい場合は、
    C:\ ... \Pocom\Example>m 2017c
または、省略して
C:\ ... \Pocom\Example>m 17c

とします。

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

とします。また、同じフォルダの中に Tra.c または Tra.cpp というファイルがあって、 それをコンパイルしたい場合は、
C:\ ... \Pocom\Example>m Tra
とします。

また、32 を指定することで64ビット対応のコンパイラで 32ビットのプログラムを作ることもできます。
C:\ ... \Pocom\Example>m 32
のようにも指定できます。
逆に m.bat に set BIT=32 とした場合にコマンドラインに 64 を指定する事で 64ビットのプログラムを作ることもできます。
32 や 64 の代わりに -m32 や -m64 としてもコマンドラインから コンパイラのビット数を変更できます。

変数のアライメントを行う ALIGN_MEM のように値を指定するマクロを定義するときは
C:\ ... \Pocom\Example>m -D"ALIGN_MEM=32"
のようにダブルクォーテーションで囲みます。
C:\ ... \Pocom\Example>m
の代わりに
C:\ ... \Pocom\Example>M
のように大文字にするとコンパイルが終わった後、キーを押されるのを待ちます。 そして、完成するプログラムも終了するときに改行キーが押されるのを待ちます。 また M.bat のアイコンをダブルクリックしてもキーが押されるのを待ちます。 そして、コンパイルエラーが起きた場合は m でも M でもキーが押されるのを待ちます。

パワーシェルの場合
C:\ ... \Pocom\Example>.\m
とすると M と同様に改行キーが押されるのを待ちますが、
C:\ ... \Pocom\Example>.\m +
のように、コマンドラインのどこかに + を入れると改行キーを待ちません。
C/C++コンパイラの場合、既定でC++としてコンパイルしますが、
C:\ ... \Pocom\Example>m +-
のように、コマンドラインのどこかに +- を入れるとC言語としてコンパイルします。
M.bat の set CPP=1 を set CPP=0 のように書き換えると、既定でC言語としてコンパイルします。
この場合、
C:\ ... \Pocom\Example>m ++
のように、コマンドラインのどこかに ++ を入れるとC++としてコンパイルします。

M.bat を複製するなどして、それを編集すると便利です。M.bat は
@echo off
echo off
set SELF=m
set ARG0=%0
set COMPILER=Gcc
set PG=Example1
set EXE=
set SUBSRCS=
set OPTIONS=
set HIT_OPTIONS=-DHIT_ENTER
set OPTIONSVC=/EHsc /O2
set OPTIONSGC=-O4
set OPTIONSBC=-O2
set OPTIONSTC=
set OPTIONSLC=
set LIBSVC=
set LIBSGC=
set LIBSBC=
set LIBSTC=
set LIBSLC=
set UTF8=0
set BIT=64
set WINDOWS=0
set OPENMP=0
set CPP=1
set HIT=1
set ANLZ=0
set RUN=0
set PARAM=
set TOOLS=.\tools
if not exist %TOOLS%\AddVer.bat set TOOLS=..\tools
if not exist %TOOLS%\AddVer.bat set TOOLS=..\..\tools
if not exist %TOOLS%\AddVer.bat set TOOLS=..\..\..\tools
if not exist %TOOLS%\AddVer.bat set TOOLS=..\..\..\..\tools
if not exist %TOOLS%\AddVer.bat set TOOLS=..\..\..\..\..\tools
if not exist %TOOLS%\AddVer.bat echo Pocom tools folder is not found.
if not exist %TOOLS%\AddVer.bat pause
if not exist %TOOLS%\AddVer.bat goto EndOfBat
set ARG=
:DoLoop
if '%1' == '' goto ArgDone
set ARG=%ARG% %1
shift
goto DoLoop
:ArgDone
call %TOOLS%\Mk^$Base %ARG%
:EndOfBat
set PG=

となっており、これを編集すればデフォルトのコンパイラ(COMPILER)やメインソースファイル(PG)や オプション(OPTIONS, PAUSE_OPTIONS, OPTIONSVC, OPTIONSGC, OPTIONSBC, OPTIONSTC, OPTIONSLC)や
追加のライブラリ(LIBSVC, LIBSGC, LIBSBC, LIBSTC, LIBSLC)の設定を変えて対応できます。
末尾が VC は Visual C++、GC は gcc,g++、BC は Borland C++、TC は Turbo C、LC は Lsic86 に対応しています。
追加のソースファイル(SUBSRCS)も指定できます。メインソースファイル(PG)には拡張子 .c や .cpp は 省略しますが、追加のソースファイル(SUBSRCS)や追加のライブラリ(LIBSVC 等)は拡張子 .c や .cpp や .lib は必要です。

WINDOWS モードをオンにしたい場合は set WINDOWS=0 を set WINDOWS=1 に書き換えます。
※ M.bat の代わりに Mk.bat を使えば WINDOWS=1 になっています。
※ M.bat を別のファイルに複製した場合は。3行目の set SELF=m を新しいファイル名に修正する必要があります。
デフォルトのソースファイルを例えば Example1.c から Tra,c に変更したい場合は set PG=Example1 という行を set PG=Tra と書き換えます。
既定で VC++ では /O2 オプションが指定されていますが /Od を渡せば最適化を行いません。
既定で gcc では -O4 オプションが指定されていますが -O0 を渡せば最適化を行いません。

m.bat や mk.bat に渡すことのできるオプションの一覧

+  パワーシェル等から m ではなく.\m のように起動してもキー入力を待たない
++ C++言語としてコンパイルする(+-の反対)
+- C言語としてコンパイルする(++の反対)
+a リンクせずにアセンブラのプログラムを出力する
+b 続く引数を SUBSRCS に追加する
+c コンソールプログラムとしてコンパイルする(+wの反対)
+e +e foo のように指定すると、foo.exe を作成する
+h 端末からから m と起動してもキー入力を待つ(Hit key)(+の反対)
+k コンパイルが終わった後も環境変数 PATH, INCLUDE, LIB を保持する(Keep env)
   exit コマンドで元の PATH, INCLUDE, LIB に戻る
+l 続く引数をリンカオプションやライブラリとして追加する
+n OpenMp を無効にする(No OpenMp)(+oの反対)
+o OpenMp を有効にする(+nの反対)
+r 成功したら自動的にプログラムを %PARAM% をパラメータにして実行する(+qの反対)
   version 8.18 以降は +r の右の文字列をパラメータに加える。
+q M.bat 等に RUN=1 としている時に自動実行を取り消す(+rの反対)
+s Utf8 ではなくシフトJISとしてコンパイルする(+uの反対)
+u Utf8 としてコンパイルする(+sの反対)
+w ウィンドウズモードでコンパイルする(+cの反対)
+y M.bat 等に ANLZ=1 としている時にコード分析を取り消す(+zの反対)
+z 可能ならコード分析を実行する(+yの反対)

m.bat や mk.bat で指定できるコンパイラの一覧

コンパイラの一覧
C++Cコンパイラ
正式名省略名正式名省略名
50 50c Visual C++ 5.0
60 60c Visual C++ 6.0
2002 02 2002c 02c Visual C++ 2002
2003 03 2003c 03c Visual C++ 2003
2005 05 2005c 05c Visual C++ 2005
2008 08 2008c 08c Visual C++ 2008
2010 10 2010c 10c Visual C++ 2010
2013 13 2013c 13c Visual C++ 2013
2017 17 2017c 17c Visual C++ 2017
2019 19 2019c 19c Visual C++ 2019
2022 22 2022c 22c Visual C++ 2022
Bcc B Bccc Bc Borland C++ 5.5.1
Gcc G Gccc Gc C:\TDM-GCC-64
Gucc Gu Guccc Guc C:\TDM-GCC-64(UTF-8ソース)
G1cc G1 G1ccc G1c C:\mingw64,C:\mingw32
Gu1ccGu1Gu1cccGu1cC:\mingw64,C:\mingw32(UTF-8ソース)
G2cc G2 G2ccc G2c C:\msys64\ucrt64
Gu2ccGu2Gu2cccGu2cC:\msys64\ucrt64(UTF-8ソース)
Lcc L Lsic86
Tcc T TurboC 1.5
Tc2 TurboC 2.01

16ビットコンパイラ

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 が高速です。
32ビット Windows でも 64ビット Windows でも、Lsic86 や TurboC を使う場合は、 Lsic86 や TurboC の本体を C:\app16 というフォルダを作成し、 そこに lsic86 , tcc や tc2 フォルダを作成して、そこに置く必要があります。
Lsic86 は http://www.lsi-j.co.jp/freesoft/
にあります。 Lsic86 の場合は C:\app16\lsic86\bin\_LCC を編集して
# LSI C-86 compiler's configuration file

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

のようにします。64ビット Windows ならば、 -DLSI_C の後に
-DMSDOS_EXE
という行を追加します。
TurboC の場合は C:\app16\tcc\TURBOC.CFG または C:\app16\tc2\TURBOC.CFG を編集して
-IC:\APP16\tcc
-LC:\APP16\tcc

または
-IC:\APP16\tc2
-LC:\APP16\tc2

のようにします。64ビット Windows ならば、
-DMSDOS_EXE=1
という行を追加します。 ただし msdos.exe 上で Lsic86 を使用する場合はコンパイルに非常に時間がかかります。
例えば、CPUが Intel Atom330 で example1.c のコンパイル時間は約2分でした。
(486版の msdos.exe 上ならば約10分)

Windows でUTF8モードでコンパイルする方法

Ubuntu はUTF8で作られているので、これから述べる Windows のような面倒な手続き無しでユニコード文字を処理することができます。
一方、Windows はデータファイルにシフトJIS以外のユニコード文字を含めたい場合にはUTF8モードにする必要があります。
シフトJISで用が足りるならばUTF8モードは使わない方が無難です。 以下、ウィンドウズでUTF8モード以外の場合をシフトJISモードと呼びます。
UTF8モードを使う場合は Windows XP 以降の Windows である必要があります。
16ビットコンパイラならば Load 関数、Output 関数、Append 関数でアスキー文字以外のファイル名処理することはできません。 ただし、後で説明する32/64ビットコンパイラならばユニコードのファイル名を処理することができます。
また、UTF8モードを使用する場合は事前に nkf.exe をダウンロードするなどして Pocom\ptools フォルダに置く必要があります。
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 に変化します。
$CmdSjis があるUTF8モードでない状態でも m.bat の set UTF8=0 を set UTF8=1 に してもUTF8のプログラムを作成できます。 また、コマンドラインで -DUTF8 または、 -DWINUTF8 を指定してもUTF8のプログラムを作成できます。
元のシフトJISモードに戻すには SetSJIS.bat をダブルクリックします。
SetUTF8.bat 2回連続して実行したり、SetSJIS.bat を2回連続して実行しても問題はありません。
$CmdUTF8 をダブルクリックして開いたコマンドプロンプトでは、起動時に chcp 65001 が実行され、 UTF8文字を表示できます。
UTF8モードの状態で M.bat でコンパイルすると、UTF8に対応した Example1.exe が作成されます。
M.bat や Mk.bat は現在UTF8モードかどうかを、$CmdUTF8 が存在するかどうかで判断してコンパイルします。
(※16ビットコンパイラでは JPN オプションが無効にされ、日本語をプログラムの中に埋め込むのが不可能な場合があります。
その場合でも、データファイルの日本語のUTF8文字は正しく処理されます。)
そうしてコンパイルできた Example1.exe の実行は、
C:\ ... \Pocom\Example>Example1 test.txt

のようにします。
Windows Vista 以前の場合、$CmdUTF8 でコマンドプロンプトを使用するときは結果に日本語があると桁位置がずれます。
リダイレクトして作ったテキストファイルや、ポコムの Output コマンドで作ったテキストファイルを、 メモ帳などで開くと桁位置はきちんと調整されているにもかかわらずです。 また、Windows Vista 以前だと、コマンドラインからバッチファイルを実行することができません。その場合、
C:\ ... \Pocom\Example>chcp 932
とすると、実行できるようになります。
一方、Windows 7 以降ならばまた、3バイトUTF8文字(基本多言語面文字)の桁位置がずれることもありません。
しかし、Windows 7 や Windows 8.1 の場合でも画面がスクロールすると表示が乱れる場合があります。 また、ダブルクォーテーションやシングルクォーテーションで全角文字を囲むと、その内側の全角文字が正しく表示されません。
さらに残念なことに、Windows 10 でも4バイトUTF8文字(サロゲートペア文字)や ひらがなカタカナ濁半濁点結合文字やIVS異体字セレクター付き文字は表示桁位置がずれます。
ただし、後で説明するウィンドウズモードにすれば、XP ならば3バイトUTF8文字(基本多言語面文字)、 Vista ならば4バイトUTF8文字(サロゲートペア文字)も正しく表示できます。
UTF8で以下のようにコマンドの最初の引数に -b オプションを指定すると
C:\ ... \Pocom\Example\Example1 -b ...

Output( )、または Append( ) でファイルを作成する場合やリダイレクトした時にBOMがファイルの先頭に書き出されます。
また、-b オプションを指定しなくても、Output( ) や Append( ) で指定するファイル名の拡張子が '.csv' と '.tsv' の時はBOMが先頭に書き出されます。
なお、UTF8のCSVファイルを正しく表示するにはエクセルは2007以降が必要です。
CSVファイルでIVS異体字セレクター付き文字等を正しく表示するにはエクセルは2013以降が必要です。

ウィンドウズモード

M.bat の代わりに WINDOWS=1 となった Mk.bat を使用すると、対応したコンパイラならばウィンドウズモードでコンパイルします。
また、コマンドラインで直接、
C:\ ... \Pocom\Example>bcc32 -W -DWINDOWS -P Example1.c
C:\ ... \Pocom\Example>cl /D WINDOWS /Tp Example1.c kernel32.lib user32.lib gdi32.lib winmm.lib comdlg32.lib
のようにしても、ウィンドウズモードでコンパイルすることができます。
C:\ ... \Pocom\Example>mk
とすると m と同様、改行キーが押されるのを待ちません。
C:\ ... \Pocom\Example>Mk
などのように大文字を混ぜると改行キーが押されるのを待ちます。
ウィンドウズモードの長所は、 です。ウィンドウズモードの短所は、 です。

ウィンドウズモードでコンパイルした .exe ファイルを Ubuntu+wine 実行する場合、

sudo apt-get install fonts-horai-umefont

として梅フォントをインストールすることを推奨します。

ASCIIモード

データファイルの中身やファイル名にASCII文字しか使用しない場合は、 -DASCII としたり、/D ASCII として、ASCII を定義すると 非ASCII文字の処理を全て無効にしてプログラムを小さくできます。 ASCIIモードとUTF8モードが同時に指定された場合はUTF8モードの方が優先されます。
ASCIIモードとは具体的には


また、JPN マクロが有効な時は JPN マクロは無効になります。

第4章 データの種類

ポコムは、多くのデータ型を持っています。

型の一覧
構造整数型コード型バイト型2バイト整数型4バイト整数型8バイト整数型半精度型単精度型倍精度型浮動小数点数型文字列型コード定義型
単純変数 INT、INTF、FIXCODEBYTETINTNINTLINTHALFFLTDBLREALSTR
ベクトル(vector) IVECCVECBVECTVECNVECLVECHVECFVECDVECRVECSVECCDEF
固定列行列(matrix) IMATCMATBMATTMATNMATLMATHMATFMATDMATRMATSMAT
可変列行列(jagged) IJAGCJAGBJAGTJAGNJAGLJAGHJAGFJAGDJAGRJAGSJAG

空白 # ; $ , を含む文字列やコードの名前を指定する時は、 " か ' で囲みます。 また、変数名/関数名と一致する文字列やコード定義を指定する時も " か ' で囲みます。" でクォートを開始した場合は "" を入れると " 1文字を表します。同様に ' でクォートを開始した場合は '' を入れると ' 1文字を表します。

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

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

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

固定列行列の大きさは、2つの整数変数で制御されます。 行数も列数も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++)
        { fputc(' ',fp); fputs(DayOfWeek[ DayMat[i][j] ],fp); }
        fprintf(fp,"\n");
    }
    FlushFp();

上の例の場合 DayMat[][] の値が DayOfWeek[] を超えると、プログラムがクラッシュ する可能性があります。以下のように書くと同じことをクラッシュせず安全に表示することができます。 以下の例では CmatStr(VAR,I,J) を使用していますが、似たような関数として
CodeStr(VAR)、CvecStr(VAR,I)、CjagStr(VAR,I,J) があります。

    for (i=0;i<N;i++) {
        for (j=0;j<N;j++)
        { fputc(' ',fp); fputs(CmatStr(DayMat,i,j),fp); }
        fprintf(fp,"\n");
    }
    FlushFp();

コードの名前には、数字・日本語等も登録できます。 社員名簿の社員番号のように数字だけの場合も登録できますし、 個人の住所録のように漢字の氏名を登録することもできます。 ただし、1つのコード定義に、同じ名前を複数登録することはできません。

Alloc("DayOfWeek") としたときには [0] [1] [2] [3] [4] [5] [6] が自動的に、 登録されます。また Print( ) で範囲外のコード型を表示させると [10] のように表示されます。 これはコード型の生の値に括弧をつけたものですが、これを [1] [2] [3] [4] [5] [6] [7] のように [1] から始めるには CDEF_BASE を1に定義してください。

32/64ビットのコンパイラで CDEF の要素数が縮小すると、それ以前に読み込んだコード型の変数はエラーになります。 縮小した場合にエラーにしたくない場合は NO_CHECK_CDEF を0以外に定義してください。
16ビットのコンパイラで縮小したときにエラーにしたいときは、CHECK_CDEF を定義してください。

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

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

空白行
行が空か、スペースかタブかカンマのみの行。データ行の終わりを表します。
注釈行
注釈行は # で始まります。注釈行は無視されます。
関数行
関数名が先頭に来て、後にパラメータが続く行です。
変数行
データを読み込む順番を決める行です。 # より右は読み込みません。
データ行
変数行で指定した順番にならんだデータの集まりです。 # より右は読み込みません。 空白 # ; $ , を含む文字列やコードの名前を指定する時は " か ' で囲みます。 また、変数名や関数名と一致する文字列やコード定義を指定する時も、 " か ' で囲みます。 また、0xで始めると16進数と見なします。 ; で行列の行末を決めます。 固定列行列を複数並べた時は、 それぞれの行末に ; を付ける必要がありますが、 可変列行列を複数並べた場合は、1つだけ ; を付けます。 空白行または $ またはファイルの終わりは配列の終わりを決めます。$ より右は読み込みません。

原則として # より右側は無視しますが、1.# の場合は無視しません。
古い Visual C++ では、浮動小数点数のでエラーが起きた場合 -1.#INF00 等が出力 されるからです。

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

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

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

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

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

第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( )を使用して効率が悪かったので仕様を変更しました。)

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

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

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

 N=3; Alloc("SV"); 
 SetStr(S,EJ("abcefg","あいうえお"));
 SetSvec(SV,0,ZeroStr)
 SetSvec(SV,1,EJ("abcefg","あいうえお"))
 AllocSvec(SV,2,11);
 memset(SV[2],'-',10);

SetStr、SetSvec、AllocSvec を使用すると NO_FAST_STR が有効の時も無効の時もOKです。 過去のバージョンの StrDup( ) や GetMemStr( ) は廃止しました。 他に SetSmat、SetSjag、AllocStr、AllocSmat、AllocSjag が使用可能です。

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

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

マクロ一覧
マクロ 説明
PROC(n,m) 引数を持たない関数
FUNC(n,m) 引数を持った関数
INT(n,w,m) 整数
INTF(n,w,f,m) 固定値整数
FIX(f) 固定値整数(簡略表現)(非負)
CODE(n,w,d,m) コード
NINT(n,w,m) 4バイト整数
LINT(n,w,m) 8バイト整数
HALF(n,w,m) 半精度浮動小数点
FLT(n,w,m) 単精度浮動小数点
DBL(n,w,m) 倍精度浮動小数点
REAL(n,w,m) 浮動小数点
STR(n,w,m) 文字列
IVEC(n,w,r,m) 整数ベクトル
CVEC(n,w,r,d,m) コード ベクトル
BVEC(n,w,r,m) 1バイト符号なし整数ベクトル
TVEC(n,w,r,m) 2バイト符号付き整数ベクトル
NVEC(n,w,r,m) 4バイト符号付き整数ベクトル
LVEC(n,w,r,m) 8バイト符号付き整数ベクトル
HVEC(n,w,r,m) 半精度浮動小数点ベクトル
FVEC(n,w,r,m) 単精度浮動小数点ベクトル
DVEC(n,w,r,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) コード固定列行列
BMAT(n,w,r,c,m) 1バイト符号なし整数固定列行列
TMAT(n,w,r,c,m) 2バイト符号付き整数固定列行列
NMAT(n,w,r,c,m) 4バイト符号付き整数固定列行列
LMAT(n,w,r,c,m) 8バイト符号付き整数固定列行列
HMAT(n,w,r,c,m) 半精度浮動小数点固定列行列
FMAT(n,w,r,c,m) 単精度浮動小数点固定列行列
DMAT(n,w,r,c,m) 倍精度浮動小数点固定列行列
RMAT(n,w,r,c,m) 浮動小数点固定列行列
SMAT(n,w,r,c,m) 文字列固定列行列
IJAG(n,w,s,m) 整数可変列行列
CJAG(n,w,s,d,m) コード可変列行列
BJAG(n,w,s,m) 1バイト符号なし整数可変列行列
TJAG(n,w,s,m) 2バイト符号付き整数可変列行列
NJAG(n,w,s,m) 4バイト符号付き整数可変列行列
LJAG(n,w,s,m) 8バイト符号付き整数可変列行列
HJAG(n,w,s,m) 半精度浮動小数点可変列行列
FJAG(n,w,s,m) 単精度浮動小数点可変列行列
DJAG(n,w,s,m) 倍精度浮動小数点可変列行列
RJAG(n,w,s,m) 浮動小数点可変列行列
SJAG(n,w,s,m) 文字列可変列行列
AUTO(t) 起動時に自動実行するデータを書く
LAST(t) 終了時に自動実行するデータを書く
LIST(t) パラメータを無しで起動したときや List を実行したときに表示する

マクロの引数
記号説明
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 を参照してください。

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

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

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

ポコム関数
名前説明
Add配列に要素を追加する。
例:INT(N,3,"")
    IVEC(L,3,N,"")
    SVEC(SVec,8,N,"")
    RVEC(RVec,308,N,"")
    RJAG(RJag,308,L,"")

    Add SVec "This is a pen." RVec 1.23 RJag 1.0 2.0 3.0

ベクトル型に追加するときは、一つの Add に対して複数の変数を追加することができる。
行列・可変列行列の場合は、一つの Add に対して一つの行列、しかも、最後に指定しなければならない。 また、データファイルでは、$ か空白行で終わらせる。複数行あっても許される。
行列・可変列行列でプログラムから Add を呼び出す時は
Add("SVec "This is a pen." RVec 1.23 RJag 1.0 2.0 3.0 $");
のように、一行でしかも $ で終わらせなければならない。(ベクトル型の場合は $ は不要)
Range 関数で指定した列数範囲に違反すればエラーとなるが、行数が違反してもエラーとはならない。
Alias変数/関数に別名をつける。日本語も指定できる。 主に AUTO マクロ内で使用される。
   例   Alias N 数 A 係数行列 B 右辺 C 作業用 X 解 Solve 実行
        Alias Alias alias Echo echo Print print System ! Format format
Append以降の出力を指定されたファイルへ追加書き込みする。- を指定すると標準出力へ書く。 + を指定すると標準エラーへ書く。 ファイル名の始まりや終わりがカンマの場合は " で囲む必要がある。
Clock起動した時からの経過時間を表示する。引数をコメントとして表示する。 コメントが不要な場合は引数に ZeorStr か "" を渡す。
Deleteファイルを削除する。 ファイル名の始まりや終わりがカンマの場合は " で囲む必要がある。
Echo文字列の表示。# よりも後ろの文字列も出力される。
Format変数の出力桁数を変更する。 出力の精度を高くしたり、 画面にたくさんのデータを表示したりするときに使用する。
整数
  100〜199:10進法で3桁ごとにカンマで区切った形式で表示する。下2桁で指定した幅で表示する。
  0〜99   :10進法で指定した幅で表示する。
  −1〜−99 :16進法で表示し、絶対値の幅で表示する。
  (100〜199にしなくても Print N;; のように ; を2つ指定すれば3桁ごとにカンマで区切った形式で表示する)

文字列・コード型
  0〜99  :Print では指定した幅で表示する。
             PrintCSV,TSV では必要に応じて引用符で囲み、常に文字列として一致した表示をする。
  −1〜−99:Print では絶対値の幅で表示する。
                 PrintCSV,TSV で値として表示するために、空文字列以外常に引用符で囲まない。
   ※PrintCSV,TSV では、
  ・32/64ビットコンパイラの場合で0以上の時 NO_CSVTSV_STR が有効なら必ず引用符で囲む。
  ・16ビットコンパイラの場合で0以上の時、必ず引用符で囲む。
   ただし、USE_CSVTSV_STR が有効のときは、必要に応じて引用符で囲む。
  (負にして PrintCSV,TSV で作成したデータはポコムの入力ファイルとして矛盾が生じる)
  (負にしなくても PrintCSV Title;; のように ; を2つ指定すれば引用符で囲まないようにできる)

浮動小数点数
  下2桁が全体の桁数を表し、百の桁が小数点以下の桁数を示す。
  -209 のように負の符号を付けると、3.14e+000 の形式で出力する。
  0または -1 に指定した時は、必要に応じた精度で表示する。

  -2 または -3 に指定した時は、16進数で表示する。幅は half:6, flt:10, dbl:18 になる。
   16進数で表示すると、浮動小数点数の値が正確に受け渡しできる。
   (-1、-2 を指定しなくても Print A;; のように ; を2つ指定すれば16進数で一時的に表示できる)

各型共通:
   ベクトル・可変列行列で、0、100、−2 を指定した場合は、
   単独で表示したときでも要素ごとに改行される。

   同時に複数の変数の桁数を変えることができる。
   例  Format  A 408   B 408   X 408
Free変数のメモリを開放して初期化する。Free を使うとサイズの変数を変えずに、 メモリを開放して、RowSize(...) を0にする。
Lap最初に呼び出された場合は Clock と同じように起動時からの経過時間を表示する。 2回目以降は前回の Lap の呼び出しからの経過時間を表示する。 引数をコメントとして表示する。コメントが不要な場合は引数に ZeorStr か "" を渡す。
LimitPrint するときに、一番右の配列を並べて表示する数を制限して折り返す。
@一番右の配列がベクトルならば、左には単純変数のみを指定できる。
A一番右の配列が固定列行列・可変列行列ならば、左には単純変数とベクトルを指定できる。
Limit 0 とすると折り返さない。 (計算ルーチンから折り返さないようにするには Limit("0"); か Limit__=0; とする。)
Limit -79 のように負の数を指定するとできるだけ79文字以内に収める(デフォルト・厳密には -(TERMINAL_X-1) )
ただし、ウィンドウズモードのときのデフォルトは -1024。
PrintCSV, PrintTSV は Limit が負の場合は OLD_EXCEL が有効なら255で折り返す。 OLD_EXCEL が無効な場合、__unix__ が定義されていれば1023で折り返す。それ以外は は16383で折り返す。
Limit 0 とすると折り返さない。 (計算ルーチンから折り返さないようにするには Limit("0"); か Limit__=0; とする。)
エクセル以外のソフトでCSV/TSVファイルを適切に折り返すためには、
例えば「libre office calc」の場合、
#define MAX_EXCEL_COL 1024
のようにする。すると1023で折り返す。あるいは、データファイルに
Limit 1023
や Limit 1020
のように書く。
Limit -1 を実行するとデフォルトに戻す。 (計算ルーチンからデフォルトに戻すには Limit("-1"); か Limit__=DEF_LIMIT__; とする。)
List変数と関数の一覧を表示する。引数は取らない。 標準変数 NoList が0以外の場合でも表示する。
Load指定されたファイルを読む。- を指定すると標準入力を読む。
Output以降の出力を指定されたファイルへ書く。 同じ名前のファイルがあるときは上書きされる。 - を指定すると標準出力へ書く。+ を指定すると標準エラーへ書く。 ファイル名の始まりや終わりがカンマの場合は " で囲む必要がある。
Print変数の表示。複数の変数を同時に指定する時は、 読み込みと同様変数の順番とサイズが合ってなければならない。
変数名に続けて ; と任意の文字列を指定することによって、 出力される変数名を一時的にその文字列に変更することが可能。
更に浮動小数点数型変数(例えば A) に対して Print A;; や Print A;SrcM; のように ; を 2つ指定すると、一時的に16進数で表示する。(SrcM は出力される変数名)
また、整数型変数に対して Print N;; や Print N;数; のように ; を2つ指定すると、 一時的に3桁ごとにカンマで区切った表示をする。('数'は出力される変数名)
折り返しの詳細については Limit の説明を参照。
PrintCSVCSVフォーマットに従って変数の値を表示する。 エクセルで読み込ませるために使用する。例えば「Output result.csv」のように した後 PrintCSV を行えば、 エクセルで開くことのできる CSV ファイルを作成できる。
この CSV ファイルはシフトJISモードでもUTF8モードでも、 ダブルクリックで正しく開くことができる。
変数名に続けて ; と任意の文字列を指定することによって、 出力される変数名を一時的にその文字列に変更することが可能。
更に文字列・コード型変数(例えば Title) に対して PrintCSV Title;; や Print Title;タイトル; のように ; を 2つ指定すると、一時的に引用符で囲まない。(タイトル は出力される変数名)
また、整数型変数に対して Print N;; や Print N;数; のように ; を2つ指定すると、 一時的に3桁ごとにカンマで区切った表示をする。('数'は出力される変数名)
折り返しの詳細については Limit の説明を参照。
文字列・コード型の引用符で囲む条件については Format の説明を参照。
PrintTSVデータの区切りをカンマからタブになることを除けば PrintCSV とほぼ同じ。
例えば「Output result.tsv」のように した後 PrintTSV を行えばエクセルで開くことのできる TSV ファイルを作成できる。 PrintTSV で作成した TSV ファイルはポコムのプログラムで読み込むことが可能。
拡張子 .tsv をエクセルに関連付けてあればシフトJISモードではダブルクリック するだけで開くことができる。UTF8モードではあらかじめ用意した「タスクバーのピン止め」や 「クイック起動」などからエクセルを起動して、そこから TSV ファイルを開けば 正しく開くことができる。
Quitプログラムを直ちに終了する。
ウィンドウズモードではログは消される。 HIT_ENTER を指定してコンパイルしても、プロンプトを表示しない。 REPORT_MEM を指定してコンパイルしても、メモリ状態を報告しない。
Range 整数、浮動小数点、コード型変数の取る値を制限する。 主に AUTO マクロ内で使用される。 範囲条件の種類として ==、!=、>、>=、<、<= が使える。
例  Range N >= 0  # N は 0 以上に制限される。

また、複数の範囲条件を設定することができる。

例  Range N > 0 <= 10 != 5
この場合 N は 1,2,3,4,6,7,8,9,10 に制限される。 (注意! 範囲条件を表す記号の前後に必ず空白を置くこと。)
例えば、Range N == 5 とすると N に 5 代入される。
Pocom Version 3 より前は何度も解除/設定できたが、 Version 3 以降は一つの変数に対して1回だけしか設定できなくなった。 理由は AUTO マクロで暴走しないように Range を設定したのに、データファイルで Range を変更することにより、 暴走するデータが作れることを防ぐため。
Reset配列を空にする。 サイズを決める変数も0になる。例えば配列 A,B を空にするには、
Reset A B
とする。これは Add 関数群を使用する前に配列 A B を初期化するのに使う。Add 関数群を使わないなら必要になる場面はない。 サイズを決める変数に0以外という Range 関数による範囲指定があったり FIX 変数であっても無視する。
ちなみに、この例と似たようなことをデーターファイル上で行うには、明示的には、
 A B
 $
分かりにくいが、空白行が配列の終わりであることを利用して単に
 A B

のように書く。ただし、これらのように書くとサイズを決める変数に0以外という範囲指定があるとエラーとなる。
行列の場合 pocom バージョン 6.05 までは列数を0にしていたが 7.01 では列数は変更しない。
Seed乱数の種を設定する。 これにより、標準関数 Unif( ) の返す乱数系列を違うものに変更できる。 引数がない場合は、現在時刻を種とする。 Seed を呼び出さずに Unif( ) を呼び出すと Seed("1") の状態から実行される。
Sort配列をソートする。
最初にオプションを指定する。省略すると -a を指定したのと同じになる。
次にソートのキーを指定する。Ivec,Cvec,Rvec,Svec が指定可能。Cdef は指定できない。
キーを Cvec にした場合は、オプションとして -a,-d,-A,-D が指定可能。
キーを Ivec,Rvec,Svec にした場合は、オプションとして -a,-d が指定可能。
以降、同時にソートする配列を指定する。なくてもかまわない。Cdef は指定できない。
N:Int DN:Int DV:Cdef[DN], L:Ivec[N], RV:Rvec[N], CV[N]<DV> SM:Smat[N][M], SJ:Sjag[N][L}
Sort RV SJ SM       # RV をキーに RV SJ SM を昇順にソートする(ascend)-a
Sort -d RV SJ SM    # RV をキーに RV SJ SM を降順にソートする(descend)-d
Sort CV RV SJ SM    # CV の値をキーに CV RV SJ SM を昇順にソートする(ascend)-a
Sort -d CV RV SJ SM # CV の値をキーに CV RV SJ SM を降順にソートする(descend)-d
Sort -A CV RV SJ SM # CV の文字列をキーに CV RV SJ SM を昇順にソートする(ascend)-A
Sort -D CV RV SJ SM # CV の文字列をキーに CV RV SJ SM を降順にソートする(descend)-D
System他のプログラムを実行する。
例:
System mkdir Temp
System は他のポコムプログラムと連携するのを主な目的として用意した。
System から呼び出されたポコムプログラムから、さらに System を使ってプログラムを 呼び出すことはできない。2重呼び出しを禁止した理由は 循環参照して無数にプログラムを実行する危険を回避するため。 例えば、
no-good.txt:
System Example1 no-good.txt
という自分自身を繰り返し実行しようとするファイル(no-good.txt)を用意して、
C:\ ... \Pocom> Example1 no-good.txt
とするとエラーとなる。

プログラムは2重呼び出しが行われるかどうかを判断するために System を実行すると最初に、 System.tmp という名前の空のファイルを作成し、実行が終了した後に消去する。
(エラー終了した場合は System.tmp に '$' を書き込み、親のプログラムに報せる。)
そして System.tmp という名前のファイルがある場合、 プログラムは System を実行できないようになっている。
従って、何らかの原因で System.tmp という名前のファイルが残ってしまった場合は、 プログラムから System を実行できなくなる。 このトラブルは、System.tmp という名前のファイルを消すことにより解決する。 System に渡すコマンドがひとつ又は複数のカンマの並びで終わる場合は、 そのカンマかカンマの並びは削除される。

Ubuntu では、
System Example1 test.txt
として、カレントフォルダに Example1 という名前のファイルがある場合 ./ が補われ、 system("./Example1 test.txt"); が呼び出される。
Load、Output、Append の行にコメントを入れる場合は、ファイル名の後に[TAB]を入れ、 その右にコメントを書くか、ファイル名を " で囲みます。

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

標準変数・定数・型
名前説明
__POCOM__ポコムのバージョン。ver 8.19 ならば 819。
__VERSTR__ポコムのバージョン。ver 8.19 ならば "8.19"
ALWAYS_FALSE常に偽。
big_tコンパイラの扱う最大の整数型。16ビットコンパイラなら long。32・64ビットコンパイラなら long long または __int64
byte,bvec,bmat,bjag常に8ビット符号なし整数。(16ビットコンパイラでは USE_BYTE、または USE_ALL_TYPES、または ASIF32 を定義する必要がある)
dbl,dvec,dmat,djag倍精度浮動小数点数。(16ビットコンパイラの場合は USE_DBL、または USE_ALL_TYPES、または ASIF32 を定義する必要がある)
EJ(E,J)マクロ JPN が1なら日本語、0なら英語に切り替えるマクロ
例:Echo(EJ("# English","# 日本語"));
データ構造の記述時や、Error、Echo、Alias 等 pocom.h で記述された関数の引数として日本語を渡すときは EJP ではなく、この EJ を使う。
EJP(E,J)マクロ JPN が1なら日本語、0なら英語に切り替えるマクロ。 BorlandC++ や古い 2008 以前の Visual C++ でUTF8モードで埋め込まれる日本語がシフトJISの場合。UTF8に変換する。
シフトJISモードの場合、または新しい Visual C++ や Ubuntu の g++ や16ビットコンパイラの場合は変換しない。
例:fputs(EJP("English\n","日本語\n"),fp);
printf、fprintf、fputs、strcpy など、pocom.h に記述されていない関数の引数として日本語を渡すときは EJ ではなく、この EJP を使う。
bool EndOfLineバッファの終わりまで読んだら true。
JP(J)BorlandC++ や古い 2008 以前の Visual C++ でUTF8モードで埋め込まれる日本語がシフトJISの場合。UTF8に変換する。
シフトJISモードの場合、または新しい Visual C++ や Ubuntu の g++ や16ビットコンパイラの場合は何もしない。
EJP(E,J) マクロの E のないもの。
例:fputs(JP("日本語\n"),fp);
double EXA#define EXA (1000000.0*1000000.0*1000000.0)
乱数をジャンプさせるときに便利。
ただし、Jump(EXA+1.0) のように指定しても 1.0 は丸められて Jump(EXA) と結果は変わらない。何故なら、 多くの場合 double は53ビットの仮数部を持つのに対し EXA は60ビットだからである。
flt,fvec,fmat,fjag単精度浮動小数点数。(16ビットコンパイラの場合は USE_FLT、または USE_ALL_TYPES、または ASIF32 を定義する必要がある)
FILE*fp出力ファイル。通常は stdout に設定されている。Append、Output で変更する。
half,hvec,hmat,hjag半精度浮動小数点数。(C++でないCコンパイラでは使用不可。または IEEE754 以外の浮動小数点数でないシステムでも使用不可)
bool HaveCmdLineFileコマンドラインで入力ファイルを指定すると true。指定しないと false。 コマンドラインで入力ファイルを指定せずに現れたダイアログでファイルをキャンセルせずに選択すると、LAST() から 呼び出される関数内では HaveCmdLineFile は true になる。
Int,ivec,imat,ijag通常の場合 int で、 #include "../pocom.h" の前に #define INT_64 とすると long long または __int64。
16ビットコンパイラで、 #include "../pocom.h" の前に #define INT_32 とすると long。
Int32_t32ビット符号付整数。
Int64_t64ビット符号付整数。
Int LastIndex 最後に呼んだ MapIndex(K,V,S), MapValue(K,V,S), MapSetSvec(K,V,S,X) で使われたインデックス値。
lint,lvec,lmat,ljag常に long long か __int64。
int Limit__Print, PrintCSV, PrintTSV をするときに、一番右の配列を並べて表示する数を制限して折り返す。
@一番右の配列がベクトルならば、左には単純変数のみを指定できる。
A一番右の配列が固定列行列・可変列行列ならば、左には単純変数とベクトルを指定できる。
大きな配列を長さ80文字以内の行に収めたい場合などに使う。 Limit__=0; とすると解除される。
Limit__=-79 のように負の値を指定すると79文字を超えないように調整する。(デフォルト)
ウィンドウズモードではデフォルトは -1024 となる。 Limit__=DEF_LIMIT__; のようにするとデフォルトの -79 か -1024 となる。
MODEL_RAW(A,B,C,D)メモリモデル別に選ぶ
A:16ビット:スモールモデル・ミディアムモデル
B:16ビット:ラージモデル・コンパクトモデル
C:32ビット
D:64ビット
MODEL_SIZE(A,B,C,D)メモリモデル別に値を選ぶ (MODEL_RAW(A,B,C,D) を括弧で囲ったもの)
Int MulAdd(Int n,Int mul,Int add)n*mul+add を返す。 オーバフローのチェックをする。
nint,nvec,nmat,njag常に 32ビット符号付整数。
int NoList0以外に設定すると変数のリストを表示する動作を抑止する。 また、ファイル選択ダイアログの出現も抑止できます。
double PETA#define PETA (1000.0*1000000.0*1000000.0)
乱数をジャンプさせるときに便利。
EXA と違い50ビットなので Jump(PETA+1.0) としても正しくジャンプする。 同じ種で PETA ずつ間隔を開けて初期化した場合4スレッドまでのマルチスレッドで正しくジャンプする。
PRI3232・64ビットコンパイラなら "" 16ビットコンパイラなら "l"。
32ビット整数(Int32_t, NINT, NVEC, NMAT, NJAG) の値を出力する時に使う。
fprintf(fp,"# %" PRI32 "d\n",(Int32_t)x); のように使う。
PRI64"ll" または "I64"。
64ビット整数(Int64_t, LINT, LVEC, LMAT, LJAG) の値を出力する時に使う。
fprintf(fp,"# %" PRI64 "d\n",(Int64_t)x); のように使う。
PRIb16ビットコンパイラなら "l"。32・64ビットコンパイラなら "ll" または "I64"。
コンパイラの扱う最大の整数型 big_t を表示するのに使用する。
fprintf(fp,"# %" PRIb "d\n",(big_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(TERA*ThreadNo,LocalSeq);
   
のように使う。
real,rvec,rmat,rjag通常の場合 double で、 #include "../pocom.h" の前に #define FLOAT_REAL とすると float。#define HALF_REAL とすると half。
FILE*Stderrエラー出力ファイル。通常は stderr が設定されている。
double TERA#define TERA (1000000.0*1000000.0)
乱数をジャンプさせるときに便利。
EXA と違い40ビットなので Jump(TERA+1.0) としても正しくジャンプする。 同じ種で TERA ずつ間隔を開けて初期化した場合4096スレッドまでのマルチスレッドで正しくジャンプする。
tint,tvec,tmat,tjag常に 16ビット符号付整数。 (16ビットコンパイラでは USE_TINT、または USE_ALL_TYPES、または ASIF32 を定義する必要がある)
Uint32_t32ビット符号なし整数。
Uint64_t64ビット符号なし整数。
UNIF_STEPUnif(),Unif_r()1回当り、何回 Rand_r() を呼び出すかを示す。
Unsigned通常の場合 unsigned で、 #include "../pocom.h" の前に #define INT_64 とすると unsigned long long または unsigned __int64。
16ビットコンパイラで、 #include "../pocom.h" の前に #define INT_32 とすると unsigned long。
wptr制御構造体の共用体へのポインタ
char ZeroStr[1]長さ0の文字列定数

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

標準関数
名前説明
AddTo???? 関数群ポコム関数 Add の下請け関数。値をベクトル型に追加したり、ベクトルを固定列・可変列行列に追加する。
void AddToIvec(ivec,Int),   void AddToImat(imat,Int,ivec), void AddToIjag(ijag,Int,ivec),
void AddToCvec(cvec,code),  void AddToCmat(cmat,Int,cvec), void AddToCjag(cjag,Int,cvec), 
void AddToBvec(bvec,byte),  void AddToBmat(bmat,Int,bvec), void AddToBjag(bjag,Int,bvec), 
void AddToTvec(tvec,short), void AddToTmat(tmat,Int,tvec), void AddToTjag(tjag,Int,tvec), 
void AddToNvec(nvec,nint),  void AddToNmat(nmat,Int,nvec), void AddToNjag(njag,Int,nvec), 
void AddToLvec(lvec,lint),  void AddToLmat(lmat,Int,lvec), void AddToLjag(ljag,Int,lvec), 
void AddToHvec(hvec,half),  void AddToHmat(hmat,Int,hvec), void AddToHjag(hjag,Int,hvec),
void AddToFvec(fvec,float), void AddToFmat(fmat,Int,fvec), void AddToFjag(fjag,Int,fvec),
void AddToDvec(fvec,double),void AddToDmat(dmat,Int,dvec), void AddToDjag(djag,Int,dvec),
void AddToRvec(rvec,real),  void AddToRmat(rmat,Int,rvec), void AddToRjag(rjag,Int,rvec),
void AddToSvec(svec,str),   void AddToSmat(smat,Int,svec), void AddToSjag(sjag,Int,svec),
void AddToCdef(cdef,str)

  例:INT(N,3,"")
      IVEC(L,3,N,"")
      IJAG(J,3,L,"")

      const Int vec[4]={1,2,3,4};
      AddToIvec(L,3);
      AddToIjag(J,4,vec);
void Alloc(const char*)配列の確保を行う。例 Alloc("C X") ;
void AllocWord(VAR)配列の確保を行う。例 AllocWord( C ) ;
void AllocWord__(wptr)配列の確保を行う。例 AllocWord__((wptr)C_ ) ;
void AllocStr(str,size_t)文字列領域の確保を行う。例 AllocStr(S,11);(S=malloc(11); のイメージ。)
void AllocSvec(svec,Int,size_t)文字列領域の確保を行う。例 AllocSvec(SV,1,11);(SV[1]=malloc(11); のイメージ。)
void AllocSmat(smat,Int,Int,size_t)文字列領域の確保を行う。例 AllocSmat(SM,1,2,11);(SM[1][2]=malloc(11); のイメージ。)
void AllocSjag(sjag,Int,Int,size_t)文字列領域の確保を行う。例 AllocSjag(SJ,1,2,11);(SJ[1][2]=malloc(11); のイメージ。)
unsigned BackRand()整数乱数を逆順に生成する。(16ビットコンパイラで使用するには BACK_RAND か ASIF32 を定義する必要がある)
unsigned BackRand64()32/64ビットコンパイラで64ビット整数乱数を逆順に生成する。
unsigned BackRand_r(Rand_t)整数乱数を逆順に生成する。マルチスレッド用。(16ビットコンパイラで使用するには BACK_RAND か ASIF32 を定義する必要がある)
unsigned BackRand64_r(Rand_t)32/64ビットコンパイラで64ビット整数乱数を逆順に生成する。マルチスレッド用。
double BackUnif()浮動小数点乱数を逆順に生成する。FLOAT_REAL が定義されているなら 24ビット精度、HALF_REAL が定義されているなら 11ビット精度。FAST_UNIF が定義されていれば 32ビット精度。それ以外は 53ビット精度。(16ビットコンパイラで使用するには BACK_RAND か ASIF32 を定義する必要がある)
double BackUnif_r(Rand_t)浮動小数点乱数を逆順に生成する。FLOAT_REAL が定義されているなら 24ビット精度、HALF_RAL が定義されているなら 11ビット精度。FAST_UNIF が定義されていれば 32ビット精度。それ以外は 53ビット精度。マルチスレッド用。(16ビットコンパイラで使用するには BACK_RAND か ASIF32 を定義する必要がある)
double BackUnif11()浮動小数点乱数を逆順に生成する。11ビット精度。(16ビットコンパイラで使用するには BACK_RAND か ASIF32 を定義する必要がある)
double BackUnif11_r(Rand_t)浮動小数点乱数を逆順に生成する。11ビット精度。マルチスレッド用。(16ビットコンパイラで使用するには BACK_RAND か ASIF32 を定義する必要がある)
double BackUnif24()浮動小数点乱数を逆順に生成する。24ビット精度。(16ビットコンパイラで使用するには BACK_RAND を定義する必要がある)
double BackUnif24_r(Rand_t)浮動小数点乱数を逆順に生成する。24ビット精度。マルチスレッド用。(16ビットコンパイラで使用するには BACK_RAND か ASIF32 を定義する必要がある)
double BackUnif32()浮動小数点乱数を逆順に生成する。32ビット精度。(16ビットコンパイラで使用するには BACK_RAND か ASIF32 を定義する必要がある)
double BackUnif32_r(Rand_t)浮動小数点乱数を逆順に生成する。32ビット精度。マルチスレッド用。(16ビットコンパイラで使用するには BACK_RAND か ASIF32 を定義する必要がある)
double BackUnif53()浮動小数点乱数を逆順に生成する。53ビット精度。(16ビットコンパイラで使用するには BACK_RAND を定義する必要がある)
double BackUnif53_r(Rand_t)浮動小数点乱数を逆順に生成する。53ビット精度。マルチスレッド用。(16ビットコンパイラで使用するには BACK_RAND か ASIF32 を定義する必要がある)
Int CdefIndex(cdef,const char*)コード定義に文字列がどの位置に登録されているかを返す。
登録されてなければ -1 を返す。
AddTo???? と組み合わせると、連想配列と呼ばれる機能を実装するのが楽になる。
Int CdefIndex__(cdef_ K_,const char*S)コード定義 K_ に文字列 S がどの位置に登録されているかを返えす。登録されてなければ -1 を返えす。
Int CdefIndex2(cdef K,const char*S)コード定義 K に文字列 S がどの位置に登録されているかを返す。
未登録ならば、エラーメッセージを表示してプログラムを終了する。
Int CdefIndex2__(cdef_ K_,const char*)コード定義 K_ に文字列 S がどの位置に登録されているかを返す。
未登録ならば、エラーメッセージを表示してプログラムを終了する。
char*CjagStr(cjag,Int,Int)コード型である可変列列整数行列の要素を対応する文字列に変換する。
void Check(const char*)配列のエラーチェックを行う。例 Check("A B") ;
bool CheckIntOverflow(n,mul,add) n*mul+add の結果がオーバーフローしたら1を返す。
バージョン 5.02 からは、この代わりに MulAdd() を使用してください。
n、add は Int 型。mul は1以上の Int 型。以下のように定義されている。
#define CheckIntOverflow(n,mul,add) ((mul)<0||(mul&&(Unsigned)(n)>\
((((Unsigned)1)<<(sizeof(Int)*8-1))-1-(add))/(mul)))
void CheckWord(VAR)配列のエラーチェックを行う。例 CheckWord( A ) ;
void CheckWord__(wptr)配列のエラーチェックを行う。例 CheckWord__((wptr)A_ ) ;
double ClockSec()プログラム開始からの経過時間を秒単位で返す。
char*CmatStr(cmat,I,J)コード型である固定列整数行列の要素を対応する文字列に変換する。
char*CodeStr(code)コード型である単純整数を対応する文字列に変換する。
void CopyArg(const char*,const char*)引数をバッファに転送する。 第一引数は親関数名、第二引数は転送する文字列。
例 CopyArg("foo",argument) ;
char*CvecStr(CV,I)コード型である整数ベクトルの要素を対応する文字列に変換する。
void DoEvents()ウィンドウズモードで時間のかかる処理をするときに、途中でこれを適当な間隔で呼び出す ことにより、閉じるボタンで終了できるようにする。
コンソールモードではなにもしない。
half dtoh(double)倍精度浮動小数点数を半精度浮動小数点数へ変換する。(C++のみ)
void FlushFp()ウィンドウズモードで fprintf(fp, ...) 等で溜まった文字列を画面に表示する。
ウィンドウズモードでは DoEvents() を内部で呼び出すので、閉じるボタンが有効になる。
これは、ウィンドウズモードの時は Print、PrintCSV、PrintTSV、Echo、List、Progress、Progress2、Clock、Lap、Error で呼び出される。
ウィンドウズモードでないときは、fflush(fp) が呼び出される。
コンソールモードでも fflush(fp); の代わりに FlushFp() を使用した方が好ましい。
void EndArg()引数の処理が終わったことをシステムに知らせる。
void Error(const char*,const char*)エラーメッセージを表示して終了する。
void FreeMem(void*)free( ) または、delete[ ] の代わりに使う。
void FreeMemRaw(void*)GetMemRaw(size_t) で確保したメモリを開放する。マルススレッドでも使用可能。
void FreeVmj(vmj*)高速線形リストを一つ開放する
void FreeWord(VAR)メモリの開放を行う。サイズを決める変数は影響を受けない。例 FreeWord( A ) ;
void FreeWord__(wptr)メモリの開放を行う。サイズを決める変数は影響を受けない。例 FreeWord__((wptr)A_ ) ;
half ftoh(float)単精度浮動小数点数を半精度浮動小数点数へ変換する。(C++のみ)
char*GetMem(Int,size_t)calloc( ) または、new[ ] の代わりに使う。領域は0で埋められる。
使い終わったら FreeMem(p) しなければならない。 ALIGN_MEM が0ならば sizeof(size_t) にアライメントされる。 ALIGN_MEM が0以外ならば、その値で返されるポインタの値とサイズがアライメントされる。
エラーが起きたらプログラムは終了する。
char*GetMemSvec(Int)calloc( ) または、new[ ] の代わりに使う。領域は0で埋められる。 使い終わったら FreeMem(p) しなければならない。 ALIGN_MEM が0以外でも sizeof(size_t) にアライメントされる。SVEC, SMAT, SJAG 専用。
エラーが起きたらプログラムは終了する。
char*GetMemRaw(size_t)calloc( ) または、new[ ] の代わりに使う。領域は0で埋められる。
エラーが起きたら0を返すだけで何もしない。 使い終わったら FreeMemRaw(p) しなければならない。マルススレッドでも使用可能。
vmj*GetVmj()高速線形リストを一つ確保する。使い終わったら FreeVmj(p) しなければならない
double htod(half)半精度浮動小数点数を単精度浮動小数点数へ変換する。(C++のみ)
float htof(half)半精度浮動小数点数を単精度浮動小数点数へ変換する。(C++のみ)
real htor(half)半精度浮動小数点数を real 型精度浮動小数点数へ変換する。(C++のみ)
char*IntStr(Int)Int, unsigned char, short,unsigned short, int, unsigned, __int64, long long 型を文字列に変換する。
void Jump(double)乱数をジャンプさせる。 (16ビットのコンパイラの場合 pocom.h をインクルードする前に JUMP_RAND か ASIF32 を定義すると使用可能。 BACK_RAND か ASIF32 を0以外に定義すると負の値で逆方向へジャンプできる。)
void Jump_r(double,Rand_t)乱数をジャンプさせる。マルチスレッド用。(16ビットのコンパイラの場合 pocom.h をインクルードする前に JUMP_RAND か ASIF32 を0以外に定義すると使用可能。 JUMP_RAND か ASIF32 を定義すると負の値で逆方向へジャンプできる。)
double LapSec()直前の Lap 関数の呼び出しからの経過時間を秒単位で返す。
double LastClock直前の Clock 関数が表示した時間を秒単位で記録している。
double LastLap直前の Lap 関数が表示した時間を秒単位で記録している。
void MapAdd(cdef K,?vec V,const char*S,? X)連想配列に X を追加する。 S が既に登録済みならメッセージを表示してプログラムを終了する。 X の型は第2引数の基本型。 memo.html を参照。
void MapAddSvec(cdef K,svec V,const char*S,const char*X)文字列連想配列に (S,X) を追加する。 S が既に登録済みならエラーメッセージを表示してプログラムを終了する。 memo.html を参照。
Int MapIndex(cdef K,?vec V,const char*S)連想配列のインデックスを返す。 memo.html を参照。
void MapSetSvec(cdef,svec,const char*,const char*)例:MapSetSvec(Key,ValueSV,"ABC","Abc");は(ValueSV["ABC"]="Abc"; のイメージ。memo.html を参照。)
? MapValue(cdef K,?vec V,const char*S)連想配列の値を返す。返り値の型は V の基本型。memo.html を参照。
? MapValue2(cdef K,?vec V,const char*S)連想配列の値を返す。返り値の型は V の基本型。 S が未登録済ならエラーメッセージを表示してプログラムを終了する。memo.html を参照。
void PrintSec(double,const char*)第一引数で指定した秒単位の時間を表示する。 時間表示の右に第二引数の文字列も表示する。
int Progress(const char*msg,Int i,Int n) 時間のかかる計算等で stderr に n が1以上なら進捗率を 0.5 秒ごとに表示する。
n が0の場合は i を表示する。特別に i が -1 ならば、"END" と表示する。
n に負の値を指定してはいけない。
ウィンドウズモードではウィンドウのタイトルバーに表示する。
ウィンドウズモードでは 0.5 秒の間に DoEvents() を4回〜7回 Progress() 内部で呼び出すので、閉じるボタンが有効になる。
マクロ NO_PROGRESS が0以外なら何も表示しない。この時ウィンドウズモードならば、DoEvents() のみ呼び出す。
msg には長さ71より長い文字列を渡しても71までしか表示されない。 日本語を渡すには EJ( ) マクロを使用すること。

進捗率を 250 ミリ秒ごとに表示するよう変更するには、pocom.h をインクルードする前に、

OLD_PROGRESS を定義すると i+1 が n ならば 100% と表示して改行する。
n が0で i が -1 ならば、"END" と表示する。
#define PROGRESS_TICK 250
を書き加える。 またはマクロ NO_INTERVAL 定義されていないか0ならば SetInterval(250); を Progress() を使用する前に呼び出すことでも変更できる。
このように頻度を SetInterval(x) として変更する場合、x は 33 ミリ秒以上でなければならない。
表示を行った時には1を返し、表示を行わなかった場合は0を返す。表示した文字列は SubBuffer__ に格納されている。
int Progress2(const char*msg,Int i,Int n,Int j,Int m) Progress( ) の2重ループ版。
i は外側のループのカウンター。n は外側のループの大きさ。
j は内側のループのカウンター。m は内側のループの大きさ。
i, n, j や m に負の値を指定してはいけない。
OLD_PROGRESS を定義すると i+1==n&&j+1==m ならば 100% と表示して改行する。
表示を行った時には1を返し、表示を行わなかった場合は0を返す。表示した文字列は SubBuffer__ に格納されている。
Uint32_t Rand()32ビットの符号なし整数乱数を返す。
Uint64_t Rand64()32/64ビットコンパイラで64ビットの符号なし整数乱数を返す。
Uint32_t Rand_f()0以外の32ビットの符号なし整数乱数を返す(高速低品質)。
Uint32_t Rand_m(N)0以外の32ビットの符号なし整数乱数を返す(高速低品質)。マルチスレッド用。N は0以上 FAST_RAND 未満。
Uint32_t Rand_r(Rand_t)マルチスレッド用の32ビットの符号なし整数乱数。
Uint64_t Rand64_r()マルチスレッド用の64ビットの符号なし整数乱数を返す。
byte ReadByte()バッファから byte を読む。(範囲チェックなし)
byte ReadByteRange(IVAR)バッファから byte を読む。 (範囲チェックを行う。IVAR は整数変数のいずれか)
code ReadCode(CDEF)バッファからコードを読む。(範囲チェックなし)
例 i = ReadCode( Node ) ;
code ReadCodeRange(CDEF,IVAR)バッファからコードを読む。 (範囲チェックを行う。IVAR は整数変数のいずれか)
例 i = ReadCodeRange( Node,From ) ;
float ReadDbl()バッファから倍精度浮動小数点数を読む。(範囲チェックなし)
float ReadDblRange(RVAR)バッファから倍精度浮動小数点数を読む。 (範囲チェックを行う。RVAR は浮動小数点数のいずれか)
float ReadFlt()バッファから単精度浮動小数点数を読む。(範囲チェックなし)
float ReadFltRange(RVAR)バッファから単精度浮動小数点数を読む。 (範囲チェックを行う。RVAR は浮動小数点数のいずれか)
half ReadHalf()バッファから半精度浮動小数点数を読む。(範囲チェックなし)
half ReadHalfRange(RVAR)バッファから半精度浮動小数点数を読む。 (範囲チェックを行う。RVAR は浮動小数点数のいずれか)
int ReadInt()バッファから整数を読む。(範囲チェックなし)
int ReadIntRange(IVAR)バッファから整数を読む。 (範囲チェックを行う。IVAR は整数変数のいずれか)
例 i = ReadIntRange( N ) ;
lint ReadLint()バッファから long long を読む。(範囲チェックなし)
lint ReadLintRange(IVAR)バッファから long long を読む。 (範囲チェックを行う。IVAR は整数変数のいずれか)
nint ReadNint()バッファから int を読む。(範囲チェックなし)
nint ReadNintRange(IVAR)バッファから int を読む。 (範囲チェックを行う。IVAR は整数変数のいずれか)
real ReadReal()バッファから浮動小数点を読む。(範囲チェックなし)
real ReadRealRange(RVAR)バッファから浮動小数点を読む。 (範囲チェックを行う。RVAR は浮動小数点数の変数のいずれか)
例 r = ReadRealRange( A ) ;
char*ReadStr()バッファから文字列を読む。
short ReadTint()バッファから short を読む。(範囲チェックなし)
short ReadTintRange(IVAR)バッファから short を読む。 (範囲チェックを行う。IVAR は整数変数のいずれか)
wptr ReadWord()バッファから変数名・関数名を読む。
void ResetLap()Lap() や LapSec() の計測開始時刻を現在時刻にする。
void ResetWord(VAR)配列を空にする。サイズを決める変数も0になる。例 ResetWord( A ) ;
void ResetWord__(wptr)配列を空にする。サイズを決める変数も0になる。例 ResetWord__((wptr)A_ ) ;
char*RealStr(real)half, float, double 型を文字列に変換する。
size_t RowSize(VAR)配列が持つ要素数を返す。ベクトルならば要素数、固定/可変列行列ならば行数を返す。
half rtoh(real)real 型浮動小数点数を半精度浮動小数点数へ変換する。(C++のみ)
int SetInterval(int)Progress(), Progress2() の設定をする。
引数が33以上の場合は Progress(), Progress2() の表示頻度をミリ秒単位で設定する。

引数が0〜32の場合は Progress(), Progress2() の初期高速化マスクをビット単位で設定する。
例えば SetInterval(9) とすると初期高速化マスクは511となり、 Progress(), Progress2() は最初の511回は時計を見にいかなくなる。
Progress(i,n) の場合は i が0の時、Progress2(i,n,j,m) の場合は i と j の両方が0の時に 高速化マスクを初期高速化マスクに設定する。
既定では初期高速化マスクは0であるが、Progress(), Progress2() を実行していくと 高速化マスクは自動調整されていく。
引数が−1〜−32の場合は Progress() あるいは Progress2() が表示をするときに 前回の表示から何回時計を見にいくかの目標値を設定する。
−1なら1回、−2なら2回〜3回、−3なら4回〜7回、−4なら8回〜15回、 −5なら16回〜31回、−6なら32回〜64回、−7なら64回〜127回となる。
指定しない時の既定値は−3の4〜7回となる。
SetInterval(-1〜-32) はあまり必要とはならないだろう。
void SetStr(SVAR,const char*)例:SetStr(S,"abc");(S=strdup("abc"); のイメージ。)
void SetSvec(SVAR,int,const char*)例:SetSvec(SV,1,"abc");(SV[1]=strdup("abc"); のイメージ。)
void SetSmat(SVAR,int,int,const char*)例:SetSmat(SM,1,2,"abc");(SM[1][2]=strdup("abc"); のイメージ。)
void SetSjag(SVAR,int,int,const char*)例:SetSjag(SJ,1,2,"abc");(SJ[1][2]=strdup("abc"); のイメージ。)
void SizeChangedBy(SIZE,BY)SIZE:INTまたはIVEC、BY:変数または関数。SIZEを変化させた原因を記録する。
void Srand(Uint32_t)乱数初期化。第一引数に種を指定する。
void Srand_r(unsigned,Rand_t)マルチスレッド用の乱数初期化。第一引数に種を指定する。
char*Strdup(const char*)strdup( ) の代わりに使う。ポコムの文字列型変数では使用しないこと。使い終わったら FreeMem( ) で解放する必要がある。
例:char*s=Strdup("abc"); ... FreeMem(s);
void SwapRow(array,int,int)行列の二つの列やベクトルの要素を入れ替える。CDEF や可変列行列には使用しないこと。
double Unif()0以上1未満の浮動小数点乱数を返す。FLOAT_REAL が定義されているなら 24ビット精度、HALF_RAL が定義されているなら 11ビット精度。FAST_UNIF が定義されていれば 32ビット精度。それ以外は 53ビット精度。
double Unif_f()0より大きく1未満の浮動小数点数乱数を返す(高速低品質)。FLOAT_REAL が定義されているなら 24ビット精度、HALF_RAL が定義されているなら 11ビット精度。FAST_UNIF が定義されていれば 32ビット精度。それ以外は 53ビット精度。
double Unif_h()0より大きく1未満の浮動小数点数乱数を返す(ハードウエア乱数)。FLOAT_REAL が定義されているなら 24ビット精度、HALF_RAL が定義されているなら 11ビット精度。FAST_UNIF が定義されていれば 32ビット精度。それ以外は 53ビット精度。
double Unif_m(N)0より大きく1未満の浮動小数点数乱数を返す(高速低品質)。FLOAT_REAL が定義されているなら 24ビット精度、HALF_RAL が定義されているなら 11ビット精度。FAST_UNIF が定義されていれば 32ビット精度。それ以外は 53ビット精度。マルチスレッド用。N は0以上 FAST_RAND 未満。
double Unif_r(Rand_t)マルチスレッド用の0以上1未満の浮動小数点乱数。FLOAT_REAL が定義されているなら 24ビット精度、HALF_RAL が定義されているなら 11ビット精度。FAST_UNIF が定義されていれば 32ビット精度。それ以外は 53ビット精度。
double Unif11()0以上1未満の浮動小数点乱数を返す。11ビット精度。
double Unif11_f()0より大きく1未満の浮動小数点数乱数を返す(高速低品質)。11ビット精度。
double Unif11_h()0より大きく1未満の浮動小数点数乱数を返す(ハードウエア乱数)。11ビット精度。
double Unif11_m(N)0より大きく1未満の浮動小数点数乱数を返す(高速低品質)。11ビット精度。マルチスレッド用。N は0以上 FAST_RAND 未満。
double Unif11_r(Rand_t)マルチスレッド用の0以上1未満の浮動小数点乱数。11ビット精度。
double Unif24()0以上1未満の浮動小数点乱数を返す。24ビット精度。
double Unif24_f()0より大きく1未満の浮動小数点数乱数を返す(高速低品質)。24ビット精度。
double Unif24_h()0より大きく1未満の浮動小数点数乱数を返す(ハードウエア乱数)。24ビット精度。
double Unif24_m(N)0より大きく1未満の浮動小数点数乱数を返す(高速低品質)。24ビット精度。マルチスレッド用。N は0以上 FAST_RAND 未満。
double Unif24_r(Rand_t)マルチスレッド用の0以上1未満の浮動小数点乱数。24ビット精度。
double Unif32()0以上1未満の浮動小数点乱数を返す。32ビット精度。
double Unif32_f()0より大きく1未満の浮動小数点数乱数を返す(高速低品質)。32ビット精度。
double Unif32_h()0より大きく1未満の浮動小数点数乱数を返す(ハードウエア乱数)。32ビット精度。
double Unif32_m(N)0より大きく1未満の浮動小数点数乱数を返す(高速低品質)。32ビット精度。マルチスレッド用。N は0以上 FAST_RAND 未満。
double Unif32_r(Rand_t)マルチスレッド用の0以上1未満の浮動小数点乱数。32ビット精度。
double Unif53()0以上1未満の浮動小数点乱数を返す。53/52ビット精度。
double Unif53_f()0より大きく1未満の浮動小数点数乱数を返す(高速低品質)。53/52ビット精度。
double Unif53_h()0より大きく1未満の浮動小数点数乱数を返す(ハードウエア乱数)。53/52ビット精度。
double Unif53_m(N)0より大きく1未満の浮動小数点数乱数を返す(高速低品質)。53/52ビット精度。マルチスレッド用。N は0以上 FAST_RAND 未満。
double Unif53_r(Rand_t)マルチスレッド用の0以上1未満の浮動小数点乱数。53/52ビット精度。
void UpdateCvar(CVAR)CVAR は CODE,CVEC,CMAT,CJAG 変数のどれかである。
計算ルーチンでで CVAR の値を ReadCode() 等で変更した後に UpdateCvar() を呼び出す。
NO_CHECK_CDEF が無効で CVAR の参照している CDEF 変数が縮小したときに、 CVAR 変数を表示してもエラーが出ないようにする。
データファイルから CVAR が読み込まれる場合、自動的に UpdateCvar( ) と同様の処理が行われるので、 これをプログラムに書く必要になる場面は滅多にないだろう。

第11章 X86_INTRIN について

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

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

ポコムのバージョン 8.15 より gcc 9 かそれ以降、または VisualC++2013 かそれ以降の 新しいコンパイラ場合、機械語ではなく組み込み関数で実現するようにしました。 これによって X86_INTRIN を定義しても Clang-Tidy 等によるコード分析が可能になりました。
ただし、NO_BUILTIN を定義すると、新しいコンパイラでも従来通りの機械語で実現します。
また、新しく RdtscpAux, MmPause1 を追加しました。
そして、32ビットでコンパイルしても Bsf64, Bsr64, Bswap64 が使用可能になりました。

機械語関数
名前説明
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等で使用可能
int HaveRdseed( )ハードウェア乱数 Rdseed32( ) と Rdseed64( ) が使用可能なら1。
第5世代の Core i7,i5,i3 以降のCPU等で使用可能
Int64_t Rdtsc( )rdtsc 命令を使って現在のクロックカウンターを得る
Int64_t CpuidRdtsc( )cpuid 命令を実行した後 rdtsc 命令を使って現在のクロックカウンターを得る。
Rdtsc( ) より時間がかかるが、より正確に計測することができる。
Int64_t Rdtscp(Uint32_t*aux)rdtscp 命令を使って現在のクロックカウンターを得る。
aux で示された場所に TSC_AUX(使用しているプロセッサの番号)を保存する。aux を0にすると保存しない。
工夫すれば Rdtscp(unsigned*aux) のほうが CpuidRdtsc( ) よりもさらに正確なクロック数を得ることができる。
unsigned RdtscpAux(void)rdtscp 命令を使って TSC_AUX(使用しているプロセッサの番号)を返す。
int Bsf(size_t)Bit scan forward を行う。0の結果は未定義。
int Bsf32(Uint32_t)Bit scan forward を行う。0の結果は未定義。
int Bsf64(Uint64_t)Bit scan forward を行う。0の結果は未定義。
int Bsr(size_t)Bit scan reverse を行う。0の結果は未定義。
int Bsr32(Uint32_t)Bit scan reverse を行う。0の結果は未定義。
int Bsr64(Uint64_t)Bit scan reverse を行う。0の結果は未定義。
int Bswap32(Uint32_t)バイトの順番を並び替える。intel486 以降
int Bswap64(Uint64_t)バイトの順番を並び替える。
void MmPause1(void) 約 10 クロックだけCPUを待機させる。 CPUにより約 70 クロックのように待機時間は大きく変化する。
void MmPause(unsigned num) 約 num×10 クロックだけCPUを待機させる。 CPUにより約 num×70 クロックのように待機時間は大きく変化する。
Uint32_t NextRdrand32(void), Rand_h()rdrand 命令を使って32ビットのハードウェア乱数を返す。エラー処理付き。
Uint64_t NextRdrand64(void), Rand64_h() NextRdrand32( ) の64ビット版。
Uint32_t NextRdseed32(void), Rand_s()rdseed 命令を使って32ビットのハードウェア乱数を返す。エラー処理付き。
Uint64_t NextRdseed64(void), Rand64_s() NextRdseed32( ) の64ビット版。
int Rdrand32(Uint32_t*val)rdrand 命令を使って32ビットのハードウェア乱数を val で示された場所に得る。
失敗すると0が返り、成功すると1が返る。
int Rdrand64(Uint64_t*val)Rdrand32() の64ビット版。
int Rdseed32(Uint32_t*val)rdseed 命令を使って32ビットのハードウェア乱数を val で示された場所に得る。
失敗すると0が返り、成功すると1が返る。
int Rdseed64(Uint64_t*val) Rdseed32() の64ビット版。
double Unif11_h()11ビット精度[0,1)の浮動小数点数ハードウエア乱数を返す
double Unif24_h()24ビット精度[0,1)の浮動小数点数ハードウエア乱数を返す
double Unif32_h()32ビット精度[0,1)の浮動小数点数ハードウエア乱数を返す
double Unif53_h()53/52ビット精度[0,1)の浮動小数点数ハードウエア乱数を返す
double Unif_h()53/52ビット精度[0,1)の浮動小数点数ハードウエア乱数を返す。
ただし FAST_UNIF が定義されてれる時は 32 ビット精度、
FLOAT_REAL が定義されていれば 24 ビット精度、
HALF_REAL が定義されていれば 11 ビット精度になる。

第12章 メモリのアライメント等の詳細

@CHECK_MEM が有効で NO_FAST_STR が無効な場合

32/64ビットコンパイラでのデフォルト。
16ビットコンパイラの場合は CHECK_MEM, ASIF32 のいずれかを有効にすると該当する。
32/64/16ビットのいずれでも NO_STR を有効にすると NO_FAST_STR が有効になるので該当せず、Aになる。

@
アライメント サイズのアライメントOpenMP 並列リージョン内
GetMem(),値の配列 ALIGN_MEM(0:sizeof(size_t))ALIGN_MEM(0:しない) 使用不可
GetMemSvec(),ポインタの配列sizeof(size_t) sizeof(size_t) 使用不可
GetMemNoAlign() sizeof(size_t) sizeof(size_t) 使用不可
GetMemRaw() しない しない 使用可
Strdup() sizeof(size_t) 1 使用不可
SetStr(),AllocStr() 等 1 1 使用不可

ACHECK_MEM が有効で NO_FAST_STR が有効な場合

32/64ビットコンパイラでは、NO_FAST_STR か NO_STR を有効にすると該当する。
16ビットコンパイラの場合は CHECK_MEM, ASIF32 のいずれかを有効にして、
NO_FAST_STR か NO_STR を有効にすると該当する。

A
アライメント サイズのアライメントOpenMP 並列リージョン内
GetMem(),値の配列 ALIGN_MEM(0:sizeof(size_t))ALIGN_MEM(0:しない) 使用不可
GetMemSvec(),ポインタの配列sizeof(size_t) sizeof(size_t) 使用不可
GetMemNoAlign() sizeof(size_t) sizeof(size_t) 使用不可
GetMemRaw() しない しない 使用可
Strdup() sizeof(size_t) 1 使用不可
SetStr() 等 sizeof(size_t) 1 使用不可
AllocStr() 等 ALIGN_MEM(0:sizeof(size_t))ALIGN_MEM(0:しない) 使用不可

BCHECK_MEM が無効で NO_FAST_STR が無効な場合

32/64ビットコンパイラでは NO_CHECK_MEM を有効にすると該当する。
16ビットコンパイラの場合はデフォルトで該当する。
32/64/16ビットのいずれでも NO_STR を有効にすると NO_FAST_STR が有効になるので該当せず、Cになる。

B
アライメント サイズのアライメントOpenMP 並列リージョン内
GetMem(),値の配列 ALIGN_MEM(0:しない)ALIGN_MEM(0:しない) 使用不可
GetMemSvec(),ポインタの配列ALIGN_MEM(0:しない)ALIGN_MEM(0:しない) 使用不可
GetMemNoAlign() ALIGN_MEM(0:しない)ALIGN_MEM(0:しない) 使用不可
GetMemRaw() しない しない 使用可
Strdup() ALIGN_MEM(0:しない)ALIGN_MEM(0:しない) 使用不可
SetStr(),AllocStr() 等 1 1 使用不可

CCHECK_MEM が無効で NO_FAST_STR が有効な場合

32/64ビットコンパイラでは NO_CHECK_MEM 有効にし、NO_FAST_STR か NO_STR を有効にすると該当する。
16ビットコンパイラの場合は NO_FAST_STR か NO_STR を有効にすると該当する。

C
アライメント サイズのアライメントOpenMP 並列リージョン内
GetMem(),値の配列 ALIGN_MEM(0:しない)ALIGN_MEM(0:しない) 使用不可
GetMemSvec(),ポインタの配列ALIGN_MEM(0:しない)ALIGN_MEM(0:しない) 使用不可
GetMemNoAlign() ALIGN_MEM(0:しない)ALIGN_MEM(0:しない) 使用不可
GetMemRaw() しない しない 使用可
Strdup() ALIGN_MEM(0:しない)ALIGN_MEM(0:しない) 使用不可
SetStr(),AllocStr() 等 ALIGN_MEM(0:しない)ALIGN_MEM(0:しない) 使用不可

ALIGN_MEM(0:sizeof(size_t)) とは ALIGN_MEM が0以外ならば ALIGN_MEM で、 ALIGN_MEM が0ならば sizeof(size_t) でアライメントすることを表します。
ALIGN_MEM(0:しない) とは ALIGN_MEM が0以外ならば ALIGN_MEM で、 ALIGN_MEM が0ならばアライメントせず new char[n] や、calloc(n,m) の返すポインタをそのまま返すか、 あるいは、返されたポインタに sizeof(size_t)+sizeof(int*) を足したポインタを返すことを意味します。

第13章 エクセルとのやり取り

ポコムのデータをグラフにしたり、計算式を埋め込んだりする時は、 エクセルが便利です。Ubuntu ではエクセルの代わりに LibreOffice calc を使います。 LibreOffice calc ではあらかじめ、「ツール」→「オートコレクトオプション」で 「言語固有のオプション」のでクォーテーションマークが全角にならないように 置換のチェックを二つとも外しておくと便利です。(https://4thsight.xyz/3253) ポコムのバージョン 5.01 からは、 カンマ区切りのデータである .csv ファイルもポコムで読み込むことができるようになったので、 タブ区切りのデータである .tsv ファイルはあまり使わなくなることと思います。

ポコムからエクセル用の .csv、.tsv データを作成して開く

ポコムのデータファイルに Output test.csv のような行を書いて、 出力先を test.csv にします。そして PrintCSV 関数や Echo 関数を使ってデータを書き出します。 すると PrintCSV はカンマ区切りのデータを作成できます。 .csv ファイルは、シフトJISモードでもUTF8モードでもダブルクリックして開くことができます。
同様に Output test.tsv のようにして PrintTSV 関数や Echo 関数を使えばタブ区切りのデータを作成できます。 .tsv ファイルはエクセルと関連付けてあればシフトJISモードであればダブルクリックして開くことができます。 .tsv ファイルはUTF8モードの場合、 エクセルと関連付けてあってダブルクリックして開くと正しく読む込むことができません。 代わりにエクセルを起動してから「ファイル」リボンなどから .tsv ファイルを開くと、 区切り文字を選ぶように要求されるので、区切り子をタブにすれば正しく読むことができます。
LibreOffice calc の場合は .csv ファイルも .tsv ファイルもダブルクリックで開くことができます。 LibreOffice calc は必要に応じて、文字コードの種類を選んだり、区切り子を選ぶことができます。 .csv ファイルの場合は「カンマ」を選び、.tsv ファイル場合「タブ」を選びます。

エクセルで表示されているデータから .csv、.tsv ファイルを書き出す方法

.csv ファイルを読み込んで開いた場合は、データを修正した後閉じるボタン「×」を 押せばそのまま修正後のデータが .csv 形式で上書きされます。
ただしUTF8モードでエクセル2013の場合は、 ユニコードテキスト(タブ区切り)でしか保存できません。
エクセル2015以降からは、 UTF8のカンマ区切り .csv ファイルに保存可能になったようです。 (私は新しいエクセルを所持していないので未確認です。)

.tsv ファイルを読み込んで開いた場合は、データを修正した後閉じるボタン「×」を 押せばそのまま修正後のデータを、エクセルは保存しようとします。 ただし、そのままだと拡張子が .txt がファイル名に加えられます。 例えば、修正前の読み込んだファイルが test.tsv ならば test.tsv.txt となります。 これを test.tsv に上書きしたい場合は、ファイル名を入力するときに「test.tsv」 ではなく「"test.tsv"」のようにダブルクォーテーションで囲みます。
.tsv ファイルを書き出すには「名前を付けて保存」で ファイルの種類:「Unicodeテキスト(*.txt)」を選んで保存してエクセルを終了します。

ポコム バージョン 5.03 からはUTF16のデータを受け付けるようになったので、 UTF16からUTF8に変更する必要はなくなりました。 ポコムでUTF16を変換する条件は次の通り。

従って日本語を含んだUTF16ファイルを正しく読み込めないケースがあります。

LibreOffice calc で .csv ファイルから読み込んだデータを修正して .csv に保存するときは、 そのまま閉じるボタン「×」を押せばそのまま修正後のデータが .csv 形式で上書きされます。
LibreOffice calc で .tsv ファイルから読み込んだデータを修正して .tsv に保存するときは、 「名前を付けて保存」でファイルの種類を「テキストCSV(.csv)」を選んで、 区切り子を「タブ」にして保存します。区切り子がタブの場合でも、拡張子は必ず .csv になるので、 面倒ですが、ファイル名の拡張子を .csv から .tsv に手動で変更します。

第14章 EJ、EJP、JP マクロの詳細

EJ(E,J) マクロは JPN が0の時は E が、1の時は J がそのまま書き出されます。 E は日本語が使えない時のためのあります。
例えば Borland C++ や Visual C++ の古いバージョンでコンパイラは、UTF8モードでコンパイルしても 日本語の文字列リテラルがシフトJISで埋め込まれます。 従ってバージョン 5.02 以前のポコムでは、古いコンパイラでUTF8モードの場合は、 強制的に JPN を0にして、日本語をプログラムに埋め込まないようにしていました。
バージョン 5.03 以降のポコムではUTF8モードで古いコンパイラでも JPN は0になりません。 そのため EJP マクロと JP マクロを用意しました。 EJP マクロも通常は EJ と同じ目的で使われます。 EJ がそのままシフトJISを返すのに対して、 EJP(E,J) は JPN が0以外の時に J をUTF8に変換した結果を返します。
JP(J) マクロは JPN が0かどうかに関わらず、シフトJISをUTF8に変換します。
シフトJISモードの場合や、UTF8モードでも文字列リテラルをUTF8にできる 新しい Visual C++ や g++ では、 EJP は EJ と全く同じで、JP(J) は J をそのまま返します。 UTF8モードで古いコンパイラを使用する時でも、データ構造の記述内や pocom.h で書かれた関数 (例えば Error、Progress、Echo、AddToCdef、SetSvec 等)に渡す場合は、内部で必要に応じて ToUtf8__() 関数が 変換するので、EJP マクロは必要なく EJ マクロを使います。
EJP マクロや JP マクロが必要なケースは fprintf 関数や strcpy 関数など、 pocom.h 内に記述されていない関数にUTF8の日本語を渡す時です。
ToUtf8__() 関数が変換する関数です。 ToUtf8__() 関数は8本(定義は BUF_UTF8__ )の戻り値のバッファを持っています。 0番目のバッファを返すことから始まり、7番目のバッファまで順に返します。 その次の ToUtf8__() 関数の戻り値は再度0番目のバッファに戻ります。
従って変換結果が保たれる寿命は短いものとなっているの注意が必要です。 main() あるいは WinMain() が呼び出されてからプログラムが終了するまでの間に グローバル文字列変数ポインタや静的文字列変数ポインタにこの EJP や JP の返す値を記録すると、 プログラムが進んでいくうちに思わぬ他の新しい変換結果に変化する危険があります。 従って、EJP や JP の返した結果は関数の引数やローカル文字列変数ポインタとして渡して、 ただちに処理すべきです。

ただし、CではなくC++ならば
static char*msg=JP("日本語");
のように main() 関数が呼び出される前に変換が行われる場合、戻り値の指す領域は プログラムが終了するまで有効です。

例えば、日本語文字列を以下のように処理していた場合、
fputs(EJ("English\n","日本語\n"),fp);
#if JPN
 fputs("日本語\n",fp);
#else
 fputs("English\n",fp);
#endif
としていたならば、 UTF8モードで古い Visual C++ や Borland C++ 5.5.1 にも対応するためには、
fputs(EJP("English\n","日本語\n"),fp);
#if JPN
fputs(JP("日本語\n"),fp);
#else
fputs("English\n",fp);
#endif
と書き換える必要があります。

第15章 乱数

●X86_INTRIN
Windows の32/64bitコンパイラでこれを定義するとハードウエア乱数を使うことができます。
Version 8.12 以降なら Rand_h() Rand64_h() Unif_h() Unif53_h() Unif32_h() Unif24_h() Unif11_h() が使用可能になります。ただし、CPUが第3世代以降の Core i シリーズである必要があります。
Version 8.15 以降なら Rand_s()、Rand64_s() が使用可能になります。ただし、CPUが第5世代以降の Core i シリーズである必要があります。
●TINYMT64 TINYMT64 を定義すると以下の乱数関数の生成方法を TinyMT32 から TinyMT64 に変更します。 Rand Rand_r BackRand BackRand_r Rand64 Rand64_r BackRand64 BackRand64_r Unif Unif_r BackUnif BackUnif_r Unif11 Unif11_r BackUnif11 BackUnif11_r Unif24 Unif24_r BackUnif24 BackUnif24_r Unif32 Unif32_r BackUnif32 BackUnif32_r Unif53 Unif53_r BackUnif53 BackUnif53_r バージョン 8.12 以降、32/64bit コンパイラならば、TinyMT32 でも Rand64, Rand64_r, BackRand64, BackRand64_r が使用可能になります。 また16 bit コンパイラの場合でも TINYMT64 を定義することができます。 TinyMT64 と TinyMT32 は異なる値を生成します。 64/16ビットコンパイラの場合 Unif()、Unif_r()、Unif53()、Unif53_r が速くなります。 32ビットコンパイラの場合や、FAST_UNIF、HALF_REAL、FLOAT_REAL が有効な場合は 遅くなります。また、ほとんどのコンパイラで Rand()、Rand_r() が遅くなり プログラムサイズが大きくなります。 ●OLD_UNIF53 TINYMT64 以外の 53/52 ビット乱数は ver 8.12 以降は ver 8.11 以前と比較して、 上位 27 ビットが同じで下位 26 ビットが異なります。 OLD_UNIF53 を定義すると ver 8.11 以前と同じになりますが少しだけ遅くなります。 ●RAND_16, RAND_32 RAND_16 を定義すると乱数の計算を16ビットで行います。 16ビットコンパイラでコンパイルすると既定で RAND_16 は定義されます。 そして全ての乱数発生が高速化します。 しかし、プログラムサイズは大きくなります。16ビットコンパイラで RAND_32 を 定義すると RAND_16 は非定義となりプログラムサイズが小さくなることがあります。 逆に32/64ビットコンパイラで RAND_16 を定義すると最大で8倍くらい遅くなります。 ●FAST_UNIF これを定義すると Unif(),Unif_m(),Unif_f(),Unif_r(),BackUnif(),BackUnif_r(), Unif_h() 関数がポコム・バージョン 8.02 以前と同じように32ビット精度になります。 FAST_UNIF を定義しない場合 ・これらの関数は53または52ビット精度になる。 ・浮動小数点数の乱数を1個発生する度に2回整数乱数を呼び出すようになる。  ただし TINYMT64, HALF_REAL, FLOAT_REAL を定義した場合1回である。  Jump(),Jump_r() を使っている場合注意が必要。 ●UNIF53_UNION, UNIF52_UNION これら2つは IEEE754 に対応したCPUで使用可能です。 さらに UNIF53_UNION は long double が 80 ビットである必要があります。 全ての Visual C++, TurboC 1.5 は long double が double と同じため、 UNIF53_UNION は使用できません。一方 TurboC 2.0、LSI-C、Borland C++、gcc は UNIF53_UNION は使用可能です。 これら2つは整数と浮動小数点数の共用体を使用して、まず [1,2) の乱数を求めて、 それから 1.0 を引いて [0,1) の乱数を返します。 UNIF52_UNION を定義すると Unif〜() 等の精度が53ビットから52ビットに減ります。 具体的には確率2分の1で53ビットの結果と比較して約1京分の1(1.1102e-16) 小さな結果を返します。一方、UNIF53_UNION の場合は53ビットのままです。 浮動小数点数演算をソフトウエアで行う16ビットコンパイラの場合はかなり高速化 します。さらに UNIF52_UNION の方が精度が落ちますが UNIF53_UNION よりも 少しだけ高速化します。 32/64ビットコンパイラの場合はどちらもほとんど高速化しません。

第16章 諸注意