前記事の通り、100桁の多倍長演算を独自で組み込んでみた。
#include <stdio.h>
#include <stdlib.h>
#define HEART_BEAT 100000
int main()
{
short a[100];
short x[2][25];
int i, j, k, l, m, n, y, z;
z = 1;
n = 0;
printf(" 1:10\n");
for (a[0]=1; a[0]<10; a[0]++)
for (a[1]=a[0]; a[1]<10; a[1]++)
for (a[2]=a[1]; a[2]<10; a[2]++)
for (a[3]=a[2]; a[3]<10; a[3]++)
for (a[4]=a[3]; a[4]<10; a[4]++)
for (a[5]=a[4]; a[5]<10; a[5]++)
for (a[6]=a[5]; a[6]<10; a[6]++)
for (a[7]=a[6]; a[7]<10; a[7]++)
for (a[8]=a[7]; a[8]<10; a[8]++)
for (a[9]=a[8]; a[9]<10; a[9]++)
for (a[10]=a[9]; a[10]<10; a[10]++)
for (a[11]=a[10]; a[11]<10; a[11]++)
for (a[12]=a[11]; a[12]<10; a[12]++)
for (a[13]=a[12]; a[13]<10; a[13]++)
for (a[14]=a[13]; a[14]<10; a[14]++)
for (a[15]=a[14]; a[15]<10; a[15]++)
for (a[16]=a[15]; a[16]<10; a[16]++)
for (a[17]=a[16]; a[17]<10; a[17]++)
for (a[18]=a[17]; a[18]<10; a[18]++)
for (a[19]=a[18]; a[19]<10; a[19]++)
for (a[20]=a[19]; a[20]<10; a[20]++)
for (a[21]=a[20]; a[21]<10; a[21]++)
for (a[22]=a[21]; a[22]<10; a[22]++)
for (a[23]=a[22]; a[23]<10; a[23]++)
for (a[24]=a[23]; a[24]<10; a[24]++)
for (a[25]=a[24]; a[25]<10; a[25]++)
for (a[26]=a[25]; a[26]<10; a[26]++)
for (a[27]=a[26]; a[27]<10; a[27]++)
for (a[28]=a[27]; a[28]<10; a[28]++)
for (a[29]=a[28]; a[29]<10; a[29]++)
for (a[30]=a[29]; a[30]<10; a[30]++)
for (a[31]=a[30]; a[31]<10; a[31]++)
for (a[32]=a[31]; a[32]<10; a[32]++)
for (a[33]=a[32]; a[33]<10; a[33]++)
for (a[34]=a[33]; a[34]<10; a[34]++)
for (a[35]=a[34]; a[35]<10; a[35]++)
for (a[36]=a[35]; a[36]<10; a[36]++)
for (a[37]=a[36]; a[37]<10; a[37]++)
for (a[38]=a[37]; a[38]<10; a[38]++)
for (a[39]=a[38]; a[39]<10; a[39]++)
for (a[40]=a[39]; a[40]<10; a[40]++)
for (a[41]=a[40]; a[41]<10; a[41]++)
for (a[42]=a[41]; a[42]<10; a[42]++)
for (a[43]=a[42]; a[43]<10; a[43]++)
for (a[44]=a[43]; a[44]<10; a[44]++)
for (a[45]=a[44]; a[45]<10; a[45]++)
for (a[46]=a[45]; a[46]<10; a[46]++)
for (a[47]=a[46]; a[47]<10; a[47]++)
for (a[48]=a[47]; a[48]<10; a[48]++)
for (a[49]=a[48]; a[49]<10; a[49]++)
for (a[50]=a[49]; a[50]<10; a[50]++)
for (a[51]=a[50]; a[51]<10; a[51]++)
for (a[52]=a[51]; a[52]<10; a[52]++)
for (a[53]=a[52]; a[53]<10; a[53]++)
for (a[54]=a[53]; a[54]<10; a[54]++)
for (a[55]=a[54]; a[55]<10; a[55]++)
for (a[56]=a[55]; a[56]<10; a[56]++)
for (a[57]=a[56]; a[57]<10; a[57]++)
for (a[58]=a[57]; a[58]<10; a[58]++)
for (a[59]=a[58]; a[59]<10; a[59]++)
for (a[60]=a[59]; a[60]<10; a[60]++)
for (a[61]=a[60]; a[61]<10; a[61]++)
for (a[62]=a[61]; a[62]<10; a[62]++)
for (a[63]=a[62]; a[63]<10; a[63]++)
for (a[64]=a[63]; a[64]<10; a[64]++)
for (a[65]=a[64]; a[65]<10; a[65]++)
for (a[66]=a[65]; a[66]<10; a[66]++)
for (a[67]=a[66]; a[67]<10; a[67]++)
for (a[68]=a[67]; a[68]<10; a[68]++)
for (a[69]=a[68]; a[69]<10; a[69]++)
for (a[70]=a[69]; a[70]<10; a[70]++)
for (a[71]=a[70]; a[71]<10; a[71]++)
for (a[72]=a[71]; a[72]<10; a[72]++)
for (a[73]=a[72]; a[73]<10; a[73]++)
for (a[74]=a[73]; a[74]<10; a[74]++)
for (a[75]=a[74]; a[75]<10; a[75]++)
for (a[76]=a[75]; a[76]<10; a[76]++)
for (a[77]=a[76]; a[77]<10; a[77]++)
for (a[78]=a[77]; a[78]<10; a[78]++)
for (a[79]=a[78]; a[79]<10; a[79]++)
for (a[80]=a[79]; a[80]<10; a[80]++)
for (a[81]=a[80]; a[81]<10; a[81]++)
for (a[82]=a[81]; a[82]<10; a[82]++)
for (a[83]=a[82]; a[83]<10; a[83]++)
for (a[84]=a[83]; a[84]<10; a[84]++)
for (a[85]=a[84]; a[85]<10; a[85]++)
for (a[86]=a[85]; a[86]<10; a[86]++)
for (a[87]=a[86]; a[87]<10; a[87]++)
for (a[88]=a[87]; a[88]<10; a[88]++)
for (a[89]=a[88]; a[89]<10; a[89]++)
for (a[90]=a[89]; a[90]<10; a[90]++)
for (a[91]=a[90]; a[91]<10; a[91]++)
for (a[92]=a[91]; a[92]<10; a[92]++)
for (a[93]=a[92]; a[93]<10; a[93]++)
for (a[94]=a[93]; a[94]<10; a[94]++)
for (a[95]=a[94]; a[95]<10; a[95]++)
for (a[96]=a[95]; a[96]<10; a[96]++)
for (a[97]=a[96]; a[97]<10; a[97]++)
for (a[98]=a[97]; a[98]<10; a[98]++)
for (a[99]=a[98]; a[99]<10; a[99]++) {
/* 枝刈り ここから */
for (i=0; i<98; i++) if ( a[i] == 2 && a[i+1] < 6 ) break;
if ( i < 98 ) for (j=i+1; j<100; j++) a[j] = 6; // 2*3=6, 2*4=8, 2*5=10
for (i=0; i<98; i++) if ( a[i] == 3 && a[i+1] == 3 ) break;
if ( i < 98 ) for (j=i+1; j<100; j++) a[j] = 5; // 3*4=2*6
for (i=0; i<98; i++) if ( a[i] == 3 && a[i+1] == 6 ) break;
if ( i < 98 ) for (j=i+1; j<100; j++) a[j] = 7; // 3*6=2*9
for (i=0; i<98; i++) if ( a[i] == 4 && a[i+1] == 4 ) break;
if ( i < 98 ) for (j=i+1; j<100; j++) a[j] = 7; // 4*4=2*8, 4*5=20, 4*6=3*8
for (i=0; i<98; i++) if ( a[i] == 5 && a[i+1] == 6 ) break;
if ( i < 98 ) for (j=i+1; j<100; j++) a[j] = 7; // 5*6=30
for (i=0; i<98; i++) if ( a[i] == 5 && a[i+1] == 8 ) break;
if ( i < 98 ) for (j=i+1; j<100; j++) a[j] = 9; // 5*8=40
for (i=0; i<98; i++) if ( a[i] == 6 && a[i+1] == 6 ) break;
if ( i < 98 ) for (j=i+1; j<100; j++) a[j] = 7;
/* 枝刈り ここまで */
for (i=0; i<25; i++) {
x[0][i] = a[i*4+0]*a[i*4+1]*a[i*4+2]*a[i*4+3];
}
y = 0;
i = 1;
x[i][24] = 10;
while ( x[i][24] > 9 ) {
y ++;
i = 1-i;
for (j=23; j>-1; j--) {
if ( x[i][j] > 1 ) {
m = 0;
for (k=24; k>j; k--) {
l = x[i][j]*x[i][k]+m;
x[i][k] = l%10000;
m = l/10000;
}
x[i][j] = m;
} else if ( x[i][j] > 0 ) {
x[i][j] = 0;
} else {
x[i][24] = 0;
break;
}
}
k = 1;
for (j=0; j<25; j++) {
if ( k == 0 ) {
x[1-i][j] = (x[i][j]/1000)*((x[i][j]/100)%10)*((x[i][j]/10)%10)*(x[i][j]%10);
} else if ( k && x[i][j] > 999 ) {
x[1-i][j] = (x[i][j]/1000)*((x[i][j]/100)%10)*((x[i][j]/10)%10)*(x[i][j]%10);
k = 0;
} else if ( k && x[i][j] > 99 ) {
x[1-i][j] = ((x[i][j]/100)%10)*((x[i][j]/10)%10)*(x[i][j]%10);
k = 0;
} else if ( k && x[i][j] > 9 ) {
x[1-i][j] = ((x[i][j]/10)%10)*(x[i][j]%10);
k = 0;
} else if ( k && x[i][j] > 0 ) {
x[1-i][j] = (x[i][j]%10);
k = 0;
} else if ( k && x[i][j] == 0 ) {
x[1-i][j] = 1;
}
}
}
if ( y == z ) {
fprintf(stderr, "%2d:", z); for (i=0; i<100; i++) if ( a[i] != 1 || i > 97 ) fprintf(stderr, "%d", a[i]); fprintf(stderr, " (not minimum)\r\n");
}
if ( y > z ) {
z = y;
printf("%2d:", z); for (i=0; i<100; i++) if ( a[i] != 1 ) printf("%d", a[i]); printf("\n");
}
if ( n == HEART_BEAT || a[0] == 9 ) {
n = 0;
printf("HB:"); for (i=0; i<100; i++) if ( a[i] != 1 ) printf("%d", a[i]); printf("\r");
}
n++;
}
printf("\nFinish!\n");
return EXIT_SUCCESS;
}
多倍長演算の四則演算全てが必要というわけではなく、必要なのは乗算(掛け算)だけである。
やってることは、手計算の手順と同じである。
これで100桁まで粘度を検索するのだが、今回の肝は桁数が増えた事によって時間がかかるということである。
つまり、どれだけ適切な枝刈りを施せるかというところにある。
前回のプログラムと同様に、初期値の各桁でネストするというところは同じである。
枝刈りの部分について説明すると、
・22…が現れたら、26…に一足飛びさせられる。
22であるならば、2*2=1*4で、14でチェック済み。
23であるならば、2*3=1*6で、16でチェック済み。
24であるならば、2*4=1*8で、18でチェック済み。
25であるならば、2*5=0になるので、粘度が伸びない。
・33…が現れたら、37…に一足飛びさせられる。
33であるならば、3*3=1*9で、19でチェック済み。
34であるならば、3*4=2*6で、26でチェック済み。
36であるならば、3*6=2*9で、29でチェック済み。
・44…が現れたら、47…に一足飛びさせられる。
44であるならば、4*4=2*8で、28でチェック済み。
45であるならば、4*5=20になるので、粘度が伸びない。
46であるならば、4*6=3*8で、38でチェック済み。
・56…が現れたら、58…に一足飛びさせられる。
56であるならば、5*6=30になるので、粘度が伸びない。
・58…が現れたら、59…に一足飛びさせられる。
58であるならば、5*8=40になるので、粘度が伸びない。
・66…が現れたら、67…に一足飛びさせられる。
66であるなばら、6*6=4*9で、49でチェック済み。
この枝刈りを施さずに実行したならば、何十時間も掛かってしまうだろう。
枝刈りをしたことで、私のパソコンでは1分も掛からずに100桁の検索を終了する。
プログラムを普通に実行しても良いのだが、いろいろ仕込んである。
まずは、同じ粘度の最小値ではない別解がみつかれば、stderrに出力する。
別解を表示したくなければ、
> mg100 2> nul
のように、 stderr を nul に出力すればよい。
同様に、別解をファイルにしたければ、
> mg100 2> mg.txt
のように、stderr を mg.txt に出力すればよい。
実行結果は、
> mg100 2> mg.txt
1:10
2:25
3:39
4:77
5:679
6:6788
7:68889
8:2677889
9:26888999
10:3778888999
11:277777788888899
HB:9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
Finish!
HBはハートビートで、長時間におけるプログラムの進捗を知るためのもの、100桁まで伸びる。
つまり、DOS窓のプロパティ→レイアウト→ウィンドウのサイズの幅を最低でも105に設定する必要がある。
さて、100桁を検索しても、粘度12は見つからなかった。
もっと桁を増やすか。
それとも粘度12は存在すらしないのか。
表示幅の限界もあるので、桁数を増やすならば、2が何個、3が何個、4が何個、5が何個、6が何個、7が何個、8が何個、9が何個といったようにすればよさそうだ。
つづく