2022年の変更 :
2009年の変更 :
このライブラリはC言語で書かれたフリーソフトウェアである。 このライブラリは、組合せの整数化と逆変換を高速に行なう。 このうち整数化のことを、最小完全ハッシュ関数ともいう。 使用メモリも少ない。 このライブラリは以下の組み合わせに対応している。
例えぱ、0 1 2 3 4 のように 5 種類(n=5,n>=0)の要素があるものと し、これから 3 つ要素(r=3,0<=r<=n)を取り出す場合を考える。取 り出し方は 10 通りあって、辞書順での番号と組合せを列挙すると、
0:(0,1,2) 1:(0,1,3) 2:(0,1,4) 3:(0,2,3) 4:(0,2,4) 5:(0,3,4) 6:(1,2,3) 7:(1,2,4) 8:(1,3,4) 9:(2,3,4)
となる。ここでは(0,1,2)と(2,1,0)を同じものと考える。目的は、
を行なうことである。この場合の簡単なプログラムを示す。
#include <stdio.h> #include "zcode.c" int main(void) { unsigned i,s; int vec[3]; s=InitComb(5,3); for (i=0;i<s;i++) { printf(" %u -> ", i); NumToComb(vec,i); printf("(%d,%d,%d)",vec[0],vec[1],vec[2]); printf(" -> %u\n", CombToNum(vec)); } return 0; }
実行結果は、以下のようになる。
0 -> (0,1,2) -> 0 1 -> (0,1,3) -> 1 2 -> (0,1,4) -> 2 3 -> (0,2,3) -> 3 4 -> (0,2,4) -> 4 5 -> (0,3,4) -> 5 6 -> (1,2,3) -> 6 7 -> (1,2,4) -> 7 8 -> (1,3,4) -> 8 9 -> (2,3,4) -> 9
InitComb(5,3) は2つの引数をともなう(n=5,r=3)。 InitComb( ) はエラーが発生すると0を返す。 InitComb( ) は入力された n と r が正しいかどうか検査する。 n と r が正しくない場合、例えば、(n=5,r=6) ならエラーとなる。 このとき、グローバル変数 CodeErrorCode は CEC_PARAMETER となる。 また、テーブルを作成中にメモリが足りなくなくなると、エラーとなる。 このとき、CodeErrorCode は CEC_MEMORY となる。
さらに、組み合わせの計算のときに、n と r が大きすぎて、 unsigned の範囲を超えオーバーフローを起こしたときも、エラーになる。 このとき、CodeErrorCode は CEC_OVERFLOW となる。 n と r が正しい場合、InitComb( ) は組み合わせが何通りあるかを返す。 例えば、(5,3)の場合は 10 を返す。InitComb( )は、また、CombToNum( ) と NumToComb( ) を高速に計算するのに必要な内部テーブルを作成する。
NumToComb(vec,i) は、unsigned i で与えられた番号から、 int vec[3] へ取り出し方を展開する。i は、0 以上 10 未満で ある。
CombToNum(vec) は、int vec[3] で与えられた取り出し方から 0 以 上 10 未満の辞書順での番号を unsigned で返す。 マクロ NO_CODE_SORT を定義すれば高速になるが vec[3] はソートされている必要がある。
性能は、例えば、ロト6のような場合(n=43,r=6)、NumToComb( ) の 一億回の実行で 6.998 秒、 NO_CODE_SORT が定義された CombToNum( ) の一億回の実行で 0.625 秒、 NO_CODE_SORT が定義されない CombToNum( ) の一億回の実行で 1.390 秒となった。 また、このときのテーブルの大きさは 1872 バイトとなった。(Core i5-10210U、Visual C++ 2008) プログラムはこちら(speed.c)
comb.c : zcode.c を使わずに、できるだけ簡単に同じ出力を得るプログラム
例えぱ、3 個の球(n=3,n>=0)があるものとし、これを 3 つの箱 (r=3,r>0)に分ける場合を考える。分け方は、10 通りあって、辞書 順での番号と組合せを列挙すると、
0:(0,0,3) 1:(0,1,2) 2:(0,2,1) 3:(0,3,0) 4:(1,0,2) 5:(1,1,1) 6:(1,2,0) 7:(2,0,1) 8:(2,1,0) 9:(3,0,0)
となる。この場合の簡単なプログラムを示す。
#include <stdio.h> #include "zcode.c" int main(void) { unsigned i,s; int vec[3]; s=InitPart(3,3); for (i=0;i<s;i++) { printf(" %u -> ", i); NumToPart(vec,i); printf("(%d,%d,%d)",vec[0],vec[1],vec[2]); printf(" -> %u\n", PartToNum(vec)); } return 0; }
実行結果は、以下のようになる。
0 -> (0,0,3) -> 0 1 -> (0,1,2) -> 1 2 -> (0,2,1) -> 2 3 -> (0,3,0) -> 3 4 -> (1,0,2) -> 4 5 -> (1,1,1) -> 5 6 -> (1,2,0) -> 6 7 -> (2,0,1) -> 7 8 -> (2,1,0) -> 8 9 -> (3,0,0) -> 9
part.c : zcode.c を使わずに、できるだけ簡単に同じ出力を得るプログラム
例えぱ、0 1 2 のように 3 種類(n=3,n>0)の要素があるものとし、こ れから 3 つ要素(r=3,r>=0)を取り出す場合を考える。ただし、同じ 要素を複数個取り出してもよいとする。取り出し方は、10 通りあっ て、辞書順での番号と組合せを列挙すると、
0:(0,0,0) 1:(0,0,1) 2:(0,0,2) 3:(0,1,1) 4:(0,1,2) 5:(0,2,2) 6:(1,1,1) 7:(1,1,2) 8:(1,2,2) 9:(2,2,2)
となる。この場合の簡単なプログラムを示す。
#include <stdio.h> #include "zcode.c" int main(void) { unsigned i,s; int vec[3]; s=InitRepe(3,3); for (i=0;i<s;i++) { printf(" %u -> ", i); NumToRepe(vec,i); printf("(%d,%d,%d)",vec[0],vec[1],vec[2]); printf(" -> %u\n", RepeToNum(vec)); } return 0; }
実行結果は、以下のようになる。
0 -> (0,0,0) -> 0 1 -> (0,0,1) -> 1 2 -> (0,0,2) -> 2 3 -> (0,1,1) -> 3 4 -> (0,1,2) -> 4 5 -> (0,2,2) -> 5 6 -> (1,1,1) -> 6 7 -> (1,1,2) -> 7 8 -> (1,2,2) -> 8 9 -> (2,2,2) -> 9
RepeToNum(vec) は、マクロ NO_CODE_SORT を定義すれば高速になるが vec[3] はソートされている必要がある。
repe.c : zcode.c を使わずに、できるだけ簡単に同じ出力を得るプログラム
例えぱ、0 1 2 3 のように 4 種類(n=4,n>0)の要素があるものとし、 これから 2 つ要素(r=2,r>0)を取り出して並べる場合を考える。並 べ方は、12 通りあって、辞書順での番号と並べ方を列挙すると、
0:(0,1) 1:(0,2) 2:(0,3) 3:(1,0) 4:(1,2) 5:(1,3) 6:(2,0) 7:(2,1) 8:(2,3) 9:(3,0) 10:(3,1) 11:(3,2)
となる。この場合の簡単なプログラムを示す。
#include <stdio.h> #include "zcode.c" int main(void) { unsigned i,s; int vec[2]; s=InitPerm(4,2); for (i=0;i<s;i++) { printf(" %2u -> ", i); NumToPerm(vec,i); printf("(%d,%d)",vec[0],vec[1]); printf(" -> %2u\n", PermToNum(vec)); } return 0; }
実行結果は、以下のようになる。
0 -> (0,1) -> 0 1 -> (0,2) -> 1 2 -> (0,3) -> 2 3 -> (1,0) -> 3 4 -> (1,2) -> 4 5 -> (1,3) -> 5 6 -> (2,0) -> 6 7 -> (2,1) -> 7 8 -> (2,3) -> 8 9 -> (3,0) -> 9 10 -> (3,1) -> 10 11 -> (3,2) -> 11
perm.c : zcode.c を使わずに、できるだけ簡単に同じ出力を得るプログラム
今まで挙げた例では、単一の内部テーブルを使っていたが、 関数名に _r を加えたバージョンを使えば、 複数のテーブルを使うことができる。 マルチスレッドなどで安全に使うことができる。
下の例は、最初のプログラムを _r バージョンを使うように 変更したものである。 エラーコードを見る場合は、CodeErrorCode ではなく、 tbl->ErrorCode を見ること。
#include <stdio.h> #include "zcode.c" int main(void) { unsigned i,s; int vec[3]; code_t tbl[1]; s=InitComb_r(tbl,5,3); for (i=0;i<s;i++) { printf(" %u -> ", i); NumToComb_r(tbl,vec,i); printf("(%d,%d,%d)",vec[0],vec[1],vec[2]); printf(" -> %u\n", CombToNum_r(tbl,vec)); } return 0; }
code_t はC言語の場合固定サイズの領域を取る。 従って、領域不足になる場合がある。 zcode.h の CODE_TABLE_SIZE を大きくしたり、 zcode.c をインクルードする前に、
#define CODE_TABLE_SIZE 32768
のように大きくすると解決する。
デフォルトの CODE_TABLE_SIZE は、10240 byte である。
(16ビットCコンパイラの場合は 2048 byte である。)
C++言語としてコンパイルした場合、メモリが足りなくなる可能性はほとんどない。
CODE_TABLE_SIZE は無視され、必要な領域が new を使って動的に確保される。
NumTo????() と ????ToNum() は共用のテーブルを読むだけで書き込むことはしない。
従って、code_t を使わずに、複数のスレッドでテーブルを共用し、Init????() を
メインスレッドで最初に使うだけの場合は、マルチスレッドで安全に使うことができる。
n と r が異なるものを同時に複数使う場合は code_t を使って、それ専用のテーブルを用意する必要がある。 複数のスレッドが頻繁に Init????_r() を呼び出す場合は、 極めて低い確率で MaxCodeTableSize が正しい値にならない可能性がある。
組み合わせの数がオーバーフローを起こすような大きな問題を扱う場合、 zcode.h の INDEX の定義を double にしたり、__int64 にしたり、あるいは、 zcode.c をインクルードする前に、
#define INDEX doubleにしたり、
#define INDEX __int64
にすれば、unsigned で扱える数値より大きなものを扱える。
下の例では 100 種類から 10 個を選ぶ 17,10,309,456,440 通りの組合せを扱っている。
下の例で NextUnif( ) は 53 ビットの精度を持つので、 どの組み合わせもほぼ等しい確率で選ばれる。
#include <stdio.h> #define INDEX double #define CODE_TABLE_SIZE 15360 #include "zcode.c" unsigned long NextRand32(void) { static unsigned long y=2463534242UL; y^=y<<13; y^=y>>17; return(y^=y<<5)&0xffffffffUL; } double NextUnif(void) { long a=(long)(NextRand32()>>5); /* 'a' has 27 random bits */ long b=(long)(NextRand32()>>6); /* 'b' has 26 random bits */ double c=a*67108864.0+b; /* 'c' has 53 random bits */ return c*(1.0/9007199254740992.0); } int main(void) { static code_t tbl[1]; INDEX sz=InitComb_r(tbl,100,10); int i,j,r[10]; if (tbl->ErrorCode==CEC_MEMORY) printf("テーブルの大きさが足りません\n"); if (tbl->ErrorCode==CEC_OVERFLOW) printf("オーバーフローが起こりました\n"); printf("テーブルの使用率= %f %%\n", 100.0*MaxCodeTableSize/CODE_TABLE_SIZE); if (sz==0) return 1; printf("sz=%.0f\n",sz); for (i=0;i<5;i++) { NumToComb_r(tbl,r,(INDEX)(NextUnif()*sz)); for (j=0;j<10;j++) printf("%2d ",r[j]); printf("\n"); } return 0; }
実行結果は、以下のようになる。
テーブルの使用率= 95.312500 % sz=17310309456440 1 15 23 25 41 44 56 79 85 92 6 7 16 19 22 35 40 42 54 65 15 17 23 32 53 65 69 74 79 92 3 11 25 39 53 56 59 70 73 82 1 17 43 49 58 69 78 82 91 95
以下は、C言語としてコンパイルし、code_t を使用した場合である。
C++としてコンパイルした場合や、〜_r 関数を使用しなければ、r が小さい場合、
オーバーフローするまで、もっと大きい n が扱える。
また、n が小さければ、この表に書いてあるものより大きい r を扱うこともできる。
InitRepe( ) で10000 を超える n を扱える r の行は省略している。
max.c : r に対する扱える n の最大値を得るプログラム
【C デフォルト 】 #define INDEX unsigned InitComb(1278, 1) = InitRepe(1278, 1) = InitPart(1277, 2) = 1278 InitComb( 639, 2) = InitRepe( 638, 2) = InitPart( 637, 3) = 203841 InitComb( 426, 3) = InitRepe( 424, 3) = InitPart( 423, 4) = 12794200 InitComb( 321, 4) = InitRepe( 318, 4) = InitPart( 317, 5) = 434171760 InitComb( 222, 5) = InitRepe( 218, 5) = InitPart( 217, 6) = 4294249674 InitComb( 123, 6) = InitRepe( 118, 6) = InitPart( 117, 7) = 4249404082 InitComb( 83, 7) = InitRepe( 77, 7) = InitPart( 76, 8) = 4151918628 InitComb( 63, 8) = InitRepe( 56, 8) = InitPart( 55, 9) = 3872894697 InitComb( 52, 9) = InitRepe( 44, 9) = InitPart( 43,10) = 3679075400 InitComb( 46,10) = InitRepe( 37,10) = InitPart( 36,11) = 4076350421 InitComb( 42,11) = InitRepe( 32,11) = InitPart( 31,12) = 4280561376 InitComb( 39,12) = InitRepe( 28,12) = InitPart( 27,13) = 3910797436 InitComb( 37,13) = InitRepe( 25,13) = InitPart( 24,14) = 3562467300 InitComb( 36,14) = InitRepe( 23,14) = InitPart( 22,15) = 3796297200 InitComb( 35,15) = InitRepe( 21,15) = InitPart( 20,16) = 3247943160 InitComb( 35,16) = InitRepe( 20,16) = InitPart( 19,17) = 4059928950 InitComb( 34,17) = InitRepe( 18,17) = InitPart( 17,18) = 2333606220 InitComb( 34,18) = InitRepe( 17,18) = InitPart( 16,19) = 2203961430 InitPerm(2558, 1) = 2558 InitPerm(1278, 2) = 1632006 InitPerm( 852, 3) = 616294200 InitPerm( 257, 4) = 4261347840 InitPerm( 86, 5) = 4179156240 InitPerm( 42, 6) = 3776965920 InitPerm( 26, 7) = 3315312000 InitPerm( 19, 8) = 3047466240 InitPerm( 16, 9) = 4151347200 InitPerm( 14,10) = 3632428800 InitPerm( 13,11) = 3113510400 InitPerm( 12,12) = 479001600 【C++ デフォルト 】 #define INDEX unsigned InitComb(2954, 3) = InitRepe(2952, 3) = InitPart(2951, 4) = 4291795704 InitComb( 568, 4) = InitRepe( 565, 4) = InitPart( 564, 5) = 4291262010 InitComb( 222, 5) = InitRepe( 218, 5) = InitPart( 217, 6) = 4294249674 InitComb( 123, 6) = InitRepe( 118, 6) = InitPart( 117, 7) = 4249404082 InitComb( 83, 7) = InitRepe( 77, 7) = InitPart( 76, 8) = 4151918628 InitComb( 63, 8) = InitRepe( 56, 8) = InitPart( 55, 9) = 3872894697 InitComb( 52, 9) = InitRepe( 44, 9) = InitPart( 43,10) = 3679075400 InitComb( 46,10) = InitRepe( 37,10) = InitPart( 36,11) = 4076350421 InitComb( 42,11) = InitRepe( 32,11) = InitPart( 31,12) = 4280561376 InitComb( 39,12) = InitRepe( 28,12) = InitPart( 27,13) = 3910797436 InitComb( 37,13) = InitRepe( 25,13) = InitPart( 24,14) = 3562467300 InitComb( 36,14) = InitRepe( 23,14) = InitPart( 22,15) = 3796297200 InitComb( 35,15) = InitRepe( 21,15) = InitPart( 20,16) = 3247943160 InitComb( 35,16) = InitRepe( 20,16) = InitPart( 19,17) = 4059928950 InitComb( 34,17) = InitRepe( 18,17) = InitPart( 17,18) = 2333606220 InitComb( 34,18) = InitRepe( 17,18) = InitPart( 16,19) = 2203961430 InitPerm(1626, 3) = 4291014000 InitPerm( 257, 4) = 4261347840 InitPerm( 86, 5) = 4179156240 InitPerm( 42, 6) = 3776965920 InitPerm( 26, 7) = 3315312000 InitPerm( 19, 8) = 3047466240 InitPerm( 16, 9) = 4151347200 InitPerm( 14,10) = 3632428800 InitPerm( 13,11) = 3113510400 InitPerm( 12,12) = 479001600 【 #define INDEX double 】 #define INDEX double InitComb( 639, 1) = InitRepe( 639, 1) = InitPart( 638, 2) = 639 InitComb( 320, 2) = InitRepe( 319, 2) = InitPart( 318, 3) = 51040 InitComb( 214, 3) = InitRepe( 212, 3) = InitPart( 211, 4) = 1610564 InitComb( 162, 4) = InitRepe( 159, 4) = InitPart( 158, 5) = 27646920 InitComb( 131, 5) = InitRepe( 127, 5) = InitPart( 126, 6) = 297602656 InitComb( 110, 6) = InitRepe( 105, 6) = InitPart( 104, 7) = 2141851635 InitComb( 96, 7) = InitRepe( 90, 7) = InitPart( 89, 8) = 11919192480 InitComb( 86, 8) = InitRepe( 79, 8) = InitPart( 78, 9) = 53060358690 InitComb( 78, 9) = InitRepe( 70, 9) = InitPart( 69,10) = 182364632450 InitComb( 72,10) = InitRepe( 63,10) = InitPart( 62,11) = 536211932256 InitComb( 67,11) = InitRepe( 57,11) = InitPart( 56,12) = 1285063345176 InitComb( 63,12) = InitRepe( 52,12) = InitPart( 51,13) = 2668424446233 InitComb( 60,13) = InitRepe( 48,13) = InitPart( 47,14) = 5166863427600 InitComb( 57,14) = InitRepe( 44,14) = InitPart( 43,15) = 7694644696200 InitComb( 55,15) = InitRepe( 41,15) = InitPart( 40,16) = 11899700525790 InitComb( 54,16) = InitRepe( 39,16) = InitPart( 38,17) = 21094923659355 InitComb( 52,17) = InitRepe( 36,17) = InitPart( 35,18) = 21945588357420 InitComb( 51,18) = InitRepe( 34,18) = InitPart( 33,19) = 27900908274925 InitComb( 50,19) = InitRepe( 32,19) = InitPart( 31,20) = 30405943383200 InitComb( 50,20) = InitRepe( 31,20) = InitPart( 30,21) = 47129212243960 InitComb( 49,21) = InitRepe( 29,21) = InitPart( 28,22) = 39049918716424 InitComb( 49,22) = InitRepe( 28,22) = InitPart( 27,23) = 49699896548176 InitComb( 48,23) = InitRepe( 26,23) = InitPart( 25,24) = 30957699535776 InitComb( 48,24) = InitRepe( 25,24) = InitPart( 24,25) = 32247603683100 InitComb( 48,25) = InitRepe( 24,25) = InitPart( 23,26) = 30957699535776 InitPerm(1279, 1) = 1279 InitPerm( 639, 2) = 407682 InitPerm( 426, 3) = 76765200 InitPerm( 320, 4) = 10290276480 InitPerm( 257, 5) = 1078121003520 InitPerm( 214, 6) = 89490569913360 InitPerm( 184, 7) = 6361571518323840 InitPerm( 102, 8) = 8841977153856000 InitPerm( 63, 9) = 8588531280067200 InitPerm( 44,10) = 9003984596006400 InitPerm( 33,11) = 7725366544896000 InitPerm( 27,12) = 8326896754176000 InitPerm( 23,13) = 7124122778572800 InitPerm( 20,14) = 3379030566912000 InitPerm( 19,15) = 5068545850368000 InitPerm( 18,16) = 3201186852864000 InitPerm( 18,17) = 6402373705728000 InitPerm( 18,18) = 6402373705728000 【C++ #define INDEX double 】 #define INDEX double InitComb(4045, 5) = InitRepe(4041, 5) = InitPart(4040, 6) = 9001965160097559 InitComb(1368, 6) = InitRepe(1363, 6) = InitPart(1362, 7) = 9003589632161124 InitComb( 645, 7) = InitRepe( 639, 7) = InitPart( 638, 8) = 8918666166467520 InitComb( 375, 8) = InitRepe( 368, 8) = InitPart( 367, 9) = 8996714454741750 InitComb( 249, 9) = InitRepe( 241, 9) = InitPart( 240,10) = 8760212643481299 InitComb( 182,10) = InitRepe( 173,10) = InitPart( 172,11) = 8543814344395330 InitComb( 143,11) = InitRepe( 133,11) = InitPart( 132,12) = 8634941152058949 InitComb( 118,12) = InitRepe( 107,12) = InitPart( 106,13) = 8531742652084314 InitComb( 101,13) = InitRepe( 89,13) = InitPart( 88,14) = 8160963550905900 InitComb( 89,14) = InitRepe( 76,14) = InitPart( 75,15) = 7632612327410136 InitComb( 81,15) = InitRepe( 67,15) = InitPart( 66,16) = 8144022047817960 InitComb( 75,16) = InitRepe( 60,16) = InitPart( 59,17) = 8550047575185300 InitComb( 70,17) = InitRepe( 54,17) = InitPart( 53,18) = 7877932561061640 InitComb( 66,18) = InitRepe( 49,18) = InitPart( 48,19) = 6848956078664700 InitComb( 64,19) = InitRepe( 46,19) = InitPart( 45,20) = 8719878125622720 InitComb( 61,20) = InitRepe( 42,20) = InitPart( 41,21) = 6236646703759395 InitComb( 60,21) = InitRepe( 40,21) = InitPart( 39,22) = 7984465725343800 InitComb( 59,22) = InitRepe( 38,22) = InitPart( 37,23) = 8964377427999630 InitComb( 58,23) = InitRepe( 36,23) = InitPart( 35,24) = 8799226775309880 InitComb( 57,24) = InitRepe( 34,24) = InitPart( 33,25) = 7522327487513475 InitComb( 56,25) = InitRepe( 32,25) = InitPart( 31,26) = 5574440580220512 InitComb( 56,26) = InitRepe( 31,26) = InitPart( 30,27) = 6646448384109072 InitComb( 56,27) = InitRepe( 30,27) = InitPart( 29,28) = 7384942649010080 InitComb( 56,28) = InitRepe( 29,28) = InitPart( 28,29) = 7648690600760440 InitComb( 56,29) = InitRepe( 28,29) = InitPart( 27,30) = 7384942649010080 InitPerm(9743, 4) = 9005406635906040 InitPerm(1554, 5) = 9004460205787200 InitPerm( 458, 6) = 8931244367878560 InitPerm( 193, 7) = 8935251187484160 InitPerm( 102, 8) = 8841977153856000 InitPerm( 63, 9) = 8588531280067200 InitPerm( 44,10) = 9003984596006400 InitPerm( 33,11) = 7725366544896000 InitPerm( 27,12) = 8326896754176000 InitPerm( 23,13) = 7124122778572800 InitPerm( 20,14) = 3379030566912000 InitPerm( 19,15) = 5068545850368000 InitPerm( 18,16) = 3201186852864000 InitPerm( 18,17) = 6402373705728000 InitPerm( 18,18) = 6402373705728000 【 #define INDEX __int64 】 InitComb( 639, 1) = InitRepe( 639, 1) = InitPart( 638, 2) = 639 InitComb( 320, 2) = InitRepe( 319, 2) = InitPart( 318, 3) = 51040 InitComb( 214, 3) = InitRepe( 212, 3) = InitPart( 211, 4) = 1610564 InitComb( 162, 4) = InitRepe( 159, 4) = InitPart( 158, 5) = 27646920 InitComb( 131, 5) = InitRepe( 127, 5) = InitPart( 126, 6) = 297602656 InitComb( 110, 6) = InitRepe( 105, 6) = InitPart( 104, 7) = 2141851635 InitComb( 96, 7) = InitRepe( 90, 7) = InitPart( 89, 8) = 11919192480 InitComb( 86, 8) = InitRepe( 79, 8) = InitPart( 78, 9) = 53060358690 InitComb( 78, 9) = InitRepe( 70, 9) = InitPart( 69,10) = 182364632450 InitComb( 72,10) = InitRepe( 63,10) = InitPart( 62,11) = 536211932256 InitComb( 67,11) = InitRepe( 57,11) = InitPart( 56,12) = 1285063345176 InitComb( 63,12) = InitRepe( 52,12) = InitPart( 51,13) = 2668424446233 InitComb( 60,13) = InitRepe( 48,13) = InitPart( 47,14) = 5166863427600 InitComb( 57,14) = InitRepe( 44,14) = InitPart( 43,15) = 7694644696200 InitComb( 55,15) = InitRepe( 41,15) = InitPart( 40,16) = 11899700525790 InitComb( 54,16) = InitRepe( 39,16) = InitPart( 38,17) = 21094923659355 InitComb( 52,17) = InitRepe( 36,17) = InitPart( 35,18) = 21945588357420 InitComb( 51,18) = InitRepe( 34,18) = InitPart( 33,19) = 27900908274925 InitComb( 50,19) = InitRepe( 32,19) = InitPart( 31,20) = 30405943383200 InitComb( 50,20) = InitRepe( 31,20) = InitPart( 30,21) = 47129212243960 InitComb( 49,21) = InitRepe( 29,21) = InitPart( 28,22) = 39049918716424 InitComb( 49,22) = InitRepe( 28,22) = InitPart( 27,23) = 49699896548176 InitComb( 48,23) = InitRepe( 26,23) = InitPart( 25,24) = 30957699535776 InitComb( 48,24) = InitRepe( 25,24) = InitPart( 24,25) = 32247603683100 InitComb( 48,25) = InitRepe( 24,25) = InitPart( 23,26) = 30957699535776 InitPerm(1279, 1) = 1279 InitPerm( 639, 2) = 407682 InitPerm( 426, 3) = 76765200 InitPerm( 320, 4) = 10290276480 InitPerm( 257, 5) = 1078121003520 InitPerm( 214, 6) = 89490569913360 InitPerm( 184, 7) = 6361571518323840 InitPerm( 162, 8) = 397988967600806400 InitPerm( 132, 9) = 9206492916741120000 InitPerm( 83,10) = 8826447557543616000 InitPerm( 58,11) = 9088747467351552000 InitPerm( 43,12) = 7347251430341222400 InitPerm( 35,13) = 9193186188426240000 InitPerm( 29,14) = 6761440164390912000 InitPerm( 25,15) = 4274473667143680000 InitPerm( 23,16) = 5129368400572416000 InitPerm( 21,17) = 2128789257154560000 InitPerm( 21,18) = 8515157028618240000 InitPerm( 20,19) = 2432902008176640000 InitPerm( 20,20) = 2432902008176640000 【C++ #define INDEX __int64 】 InitComb(4337, 6) = InitRepe(4332, 6) = InitPart(4331, 7) = 9210884681005865704 InitComb(1733, 7) = InitRepe(1727, 7) = InitPart(1726, 8) = 9202167919706100768 InitComb( 887, 8) = InitRepe( 880, 8) = InitPart( 879, 9) = 9207044098280898870 InitComb( 534, 9) = InitRepe( 526, 9) = InitPart( 525,10) = 9092292741062601356 InitComb( 361,10) = InitRepe( 352,10) = InitPart( 351,11) = 9134638038697149616 InitComb( 265,11) = InitRepe( 255,11) = InitPart( 254,12) = 9187507719876570240 InitComb( 206,12) = InitRepe( 195,12) = InitPart( 194,13) = 8795548359217331075 InitComb( 169,13) = InitRepe( 157,13) = InitPart( 156,14) = 9176358300744339432 InitComb( 143,14) = InitRepe( 130,14) = InitPart( 129,15) = 8887821571512103935 InitComb( 125,15) = InitRepe( 111,15) = InitPart( 110,16) = 9064807833193439800 InitComb( 111,16) = InitRepe( 96,16) = InitPart( 95,17) = 8156833787798824590 InitComb( 101,17) = InitRepe( 85,17) = InitPart( 84,18) = 7995995501984016450 InitComb( 94,18) = InitRepe( 77,18) = InitPart( 76,19) = 9007607943130625829 InitComb( 88,19) = InitRepe( 70,19) = InitPart( 69,20) = 8910491434304783400 InitComb( 83,20) = InitRepe( 64,20) = InitPart( 63,21) = 8179808679272664720 InitComb( 79,21) = InitRepe( 59,21) = InitPart( 58,22) = 7449416156804224460 InitComb( 76,22) = InitRepe( 55,22) = InitPart( 54,23) = 7266758081613043600 InitComb( 74,23) = InitRepe( 52,23) = InitPart( 51,24) = 8249183865278257824 InitComb( 72,24) = InitRepe( 49,24) = InitPart( 48,25) = 7950261662089028100 InitComb( 70,25) = InitRepe( 46,25) = InitPart( 45,26) = 6455761770304780752 InitComb( 69,26) = InitRepe( 44,26) = InitPart( 43,27) = 7023301266595310928 InitComb( 68,27) = InitRepe( 42,27) = InitPart( 41,28) = 6808417652963570336 InitComb( 67,28) = InitRepe( 40,28) = InitPart( 39,29) = 5864393356544251760 InitComb( 67,29) = InitRepe( 39,29) = InitPart( 38,30) = 7886597962249166160 InitComb( 66,30) = InitRepe( 37,30) = InitPart( 36,31) = 5516694892996182896 InitComb( 66,31) = InitRepe( 36,31) = InitPart( 35,32) = 6406484391866534976 InitComb( 66,32) = InitRepe( 35,32) = InitPart( 34,33) = 7007092303604022630 InitComb( 66,33) = InitRepe( 34,33) = InitPart( 33,34) = 7219428434016265740 InitComb( 66,34) = InitRepe( 33,34) = InitPart( 32,35) = 7007092303604022630 InitPerm(6210, 5) = 9220585194601079040 InitPerm(1450, 6) = 9198343437354036000 InitPerm( 515, 7) = 9222879462222182400 InitPerm( 238, 8) = 9140646456023322240 InitPerm( 132, 9) = 9206492916741120000 InitPerm( 83,10) = 8826447557543616000 InitPerm( 58,11) = 9088747467351552000 InitPerm( 43,12) = 7347251430341222400 InitPerm( 35,13) = 9193186188426240000 InitPerm( 29,14) = 6761440164390912000 InitPerm( 25,15) = 4274473667143680000 InitPerm( 23,16) = 5129368400572416000 InitPerm( 21,17) = 2128789257154560000 InitPerm( 21,18) = 8515157028618240000 InitPerm( 20,19) = 2432902008176640000 InitPerm( 20,20) = 2432902008176640000 【#define INDEX unsigned short 】 InitComb(2556, 1) = InitRepe(2556, 1) = InitPart(2555, 2) = 2556 InitComb( 362, 2) = InitRepe( 361, 2) = InitPart( 360, 3) = 65341 InitComb( 74, 3) = InitRepe( 72, 3) = InitPart( 71, 4) = 64824 InitComb( 36, 4) = InitRepe( 33, 4) = InitPart( 32, 5) = 58905 InitComb( 25, 5) = InitRepe( 21, 5) = InitPart( 20, 6) = 53130 InitComb( 21, 6) = InitRepe( 16, 6) = InitPart( 15, 7) = 54264 InitComb( 19, 7) = InitRepe( 13, 7) = InitPart( 12, 8) = 50388 InitComb( 18, 8) = InitRepe( 11, 8) = InitPart( 10, 9) = 43758 InitComb( 18, 9) = InitRepe( 10, 9) = InitPart( 9,10) = 48620 InitComb( 18,10) = InitRepe( 9,10) = InitPart( 8,11) = 43758 InitPerm(5116, 1) = 5116 InitPerm( 256, 2) = 65280 InitPerm( 41, 3) = 63960 InitPerm( 17, 4) = 57120 InitPerm( 11, 5) = 55440 InitPerm( 9, 6) = 60480 InitPerm( 8, 7) = 40320 InitPerm( 8, 8) = 40320 【C++ #define INDEX unsigned short 】 #define INDEX unsigned short InitComb( 362, 2) = InitRepe( 361, 2) = InitPart( 360, 3) = 65341 InitComb( 74, 3) = InitRepe( 72, 3) = InitPart( 71, 4) = 64824 InitComb( 36, 4) = InitRepe( 33, 4) = InitPart( 32, 5) = 58905 InitComb( 25, 5) = InitRepe( 21, 5) = InitPart( 20, 6) = 53130 InitComb( 21, 6) = InitRepe( 16, 6) = InitPart( 15, 7) = 54264 InitComb( 19, 7) = InitRepe( 13, 7) = InitPart( 12, 8) = 50388 InitComb( 18, 8) = InitRepe( 11, 8) = InitPart( 10, 9) = 43758 InitComb( 18, 9) = InitRepe( 10, 9) = InitPart( 9,10) = 48620 InitComb( 18,10) = InitRepe( 9,10) = InitPart( 8,11) = 43758 InitPerm( 256, 2) = 65280 InitPerm( 41, 3) = 63960 InitPerm( 17, 4) = 57120 InitPerm( 11, 5) = 55440 InitPerm( 9, 6) = 60480 InitPerm( 8, 7) = 40320 InitPerm( 8, 8) = 40320
このプログラムを理解しようとするならば、重複組み合わせから始める とよい。具体的には test.c を実行し repe demo を選択して、 重複組み合わせと出力される表の対応関係を見るとよい。
プログラムの NumTo????( ) と ????ToNum( ) は表を使っている。表 の使用方法は、関数が短いので容易に理解できる(と思う)。
一方、Init????( )が行っている表の作成はかなり複雑で、私も 試行錯誤でこの方法を見つけた。
perm は後から付け加えた例外的なもので、計算の方法が他の 3つとは大幅に違い、表も1つしか持っていない。