/*
max.c r に対する最大の n の値と組合せの総数を求める
   programmed by Isaku WADA isaku@pb4.so-net.ne.jp
*/
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#if !defined(INDEX)
 #define INDEX unsigned
#endif
#define TO_STR_BASE(X) #X
#define TO_STR(X) TO_STR_BASE(X)
#define INDEX_STR TO_STR(INDEX)
#include "zcode.c"

/*
 const char*i2a(INDEX value)

 INDEX 型を10進文字列に変換する。

float
最小表現不可能正整数                     16,777,217
i2a() の最大表示可能整数 99,999,993,536,462,043,136

double
最小表現不可能正整数          9,007,199,254,740,993
i2a() の最大表示可能整数 99,999,999,999,999,983,616

long double ( Visual C++ では long double は double と同一 )
最小表現不可能正整数     18,446,744,073,709,551,617
i2a() の最大表示可能整数 99,999,999,999,999,999,992

char
-128 〜 127

unsigned char
0 〜 255

short
-32,768 〜 32,767

unsigned short
0 〜 65,535

int ( 16ビットコンパイラでは long )
-2,147,483,648 〜 2,147,483,647

unsigned ( 16ビットコンパイラでは unsigned long )
0 〜 4,294,967,295

__int64 ( long long )
-9,223,372,036,854,775,808 〜 9,223,372,036,854,775,807

unsigned __int64 ( unsigned long long )
0 〜 18,446,744,073,709,551,615

*/

const char*i2a(INDEX value) {
    enum { MX=20, SW=8 }; static int mx,ok,sw; static INDEX zero,tbl[MX];
    static char buf[SW][MX+2]; char*ret=buf[sw++%SW]+1,*p=ret; int i,g=0;
    if (mx==0) {
        INDEX x,x2,x4,x8,x10=0;
        for (tbl[0]=x=1,mx=1;mx<=MX;mx++) {
            if ((x2=x+x)<x)     break;
            if ((x4=x2+x2)<x2)  break;
            if ((x8=x4+x4)<x4)  break;
            if ((x10=x8+x2)<x8) break;
            x=x10;
            if (mx<MX) tbl[mx]=x;
        }
        x=x10-1;
        if (x10-x!=1||mx<=MX) ok=1;
        if (mx==MX+1) mx=MX;
        /* printf("ok=%d mx=%d tbl[mx-1]=%.0f\n",ok,mx,(double)tbl[mx-1]); */
    }
    if (value<zero) {
        *--ret='-'; value*=(INDEX)(-1);
        if (value<zero) { g=1; value--; }
    }
    if (ok==0||value/tbl[mx-1]>=10) return"(error)";
    for (i=0;i<mx;i++) if (value<tbl[i]) break;
    if (i==0) return"0";
    while (--i>=0) { 
        INDEX t=tbl[i]; int v=(int)(value/t);
        *p++=(char)('0'+v); value-=(INDEX)(t*v);
        if (g) { g=0; value++; }
    }
    *p=0; return ret;
}

/*┌───────┐
 │メインルーチン│
 └───────┘*/
int main(void) {
    int n,r,bits; INDEX p,q=0; FILE*fp; char fn[100]; code_t t[1];
    INDEX minus_one=(INDEX)-1;
    if (strcmp(INDEX_STR,"long double")==0) bits=(sizeof(INDEX)==8?53:80);
    else if (strcmp(INDEX_STR,"double")==0) bits=53;
    else if (strcmp(INDEX_STR,"float")==0)  bits=24;
    else bits=(int)sizeof(INDEX)*8-(minus_one<1);
    sprintf(fn,"max%d-%d.txt",(int)sizeof(size_t)*8,bits);
    if ((fp=fopen(fn,"w"))==0) { printf("'%s' cannot open\n",fn); return 1; }
#if defined(__cplusplus)
    printf("C++ %d\n",(int)sizeof(size_t)*8);
#else
    printf("C %d\n",(int)sizeof(size_t)*8);
#endif
    printf("#define INDEX " INDEX_STR "\n");
    fprintf(fp,"#define INDEX " INDEX_STR "\n");
    for (r=1;r<100;r++) {
        for (n=1;n<9999;n++) {
            p=InitRepe_r(t,n,r);
            if (p==0){
                if (n<r) break;
                fprintf(fp,"InitComb(%4d,%2d) = ",(n-1)+r-1,r);
                fprintf(fp,"InitRepe(%4d,%2d) = ",(n-1),r);
                fprintf(fp,"InitPart(%4d,%2d) = ",(n-1)-1,r+1);
                fprintf(fp,"%s\n",i2a(q));
                break;
            }
            q=p;
        }
        if (n<r) break;
    }
    for (r=1;r<100;r++) {
        if ((q=InitPerm_r(t,r,r))==0) break;
        for (n=r;n<9999;n++) {
            p=InitPerm_r(t,n,r);
            if (p==0){
                if (q) {
                    fprintf(fp,"InitPerm(%4d,%2d) = ",(n-1),r);
                    fprintf(fp,"%s\n",i2a(q));
                    break;
                }
            }
            q=p;
        }
    }
    fclose(fp);
    printf("Wrote '%s'\n",fn);
    return 0;
}