/*****************************************************************************/ /* */ /* FIND CYCLES IN THE 3N+C SEQUENCE */ /* 11/17/13 (dkc) */ /* */ /* This C program finds cycles in the 3n+c sequence. Attachment points are */ /* output. Double-precision (64-bit) words are used. Robert Floyd's */ /* cycle finding algorithm (Knuth 1969, "The Art of Computer Programming, */ /* Vol. 1: Fundamental Algorithms", pp. 4-7, exercise 7) is used. */ /* */ /* The output array "sinp" contains the attachment points. The values in */ /* the output array "cflag" indicate which attachment points are associated */ /* with a cycle. The output array "size" gives the total number of */ /* attachment points for each c value. The output array "cval" gives the */ /* corresponding c values. The output variable "numbc" gives the number */ /* of c values. After some minor editing to fill in array sizes, the */ /* output can be made into an "include" file for other programs. */ /* */ /* Output "big" cycles indicate whether parameters (in particular "limit") */ /* need to be modified to find cycles that may have been missed. "L" is */ /* is the number of even elements in the cycles, "K" is the number of odd */ /* elements, and "a" is the number of primary attachment points. "count" */ /* gives the number of cycles found for a given c value. Cycles without */ /* attachment points are also found. */ /* */ /*****************************************************************************/ #include <math.h> #include "table4.h" unsigned int carry(unsigned int a, unsigned int b, unsigned int sum); unsigned int lmbd(unsigned int mode, unsigned int a); void add64(unsigned int *a, unsigned int *b); void sub64(unsigned int *a, unsigned int *b); void div64_32(unsigned int *dividend, unsigned int *quotient, unsigned int divisor); void mul64_32(unsigned int a0, unsigned int a2, unsigned int m0, unsigned int *product); unsigned int jumps(unsigned int K0, unsigned int K1, unsigned int iters, unsigned int c, unsigned int max, unsigned int *output); unsigned int cycle(unsigned int K0, unsigned int K1, unsigned int max, unsigned int c, unsigned int *output); unsigned int regen(unsigned int K0, unsigned int K1, unsigned int *output, unsigned int c); unsigned int check(unsigned int gop, unsigned int MIN0, unsigned int MIN1, unsigned int *gom, unsigned int gomind); void dummy(unsigned int A, unsigned int B, unsigned int C, unsigned int D, unsigned int E, unsigned int F, unsigned int G, unsigned int H); far unsigned int error[10]; far unsigned int clkout[10000*4]; far unsigned int output[5]; far unsigned char cyc[90000]; far unsigned int out[90000]; far unsigned int lopcnt[500]; far unsigned int factor[400]; far unsigned int bigcyc[200*5]; far unsigned int bigatt[400*3]; far unsigned int gom[10000*3]; far unsigned int noatt[1000*3]; far unsigned int oddout[1000*4]; far unsigned int cval[400]; int main () { // unsigned int cstart=1; // beginning c value unsigned int cend=499; // ending c value unsigned int iters=1; // number of "jumps" from the initial odd integer // divisible by 3. The parameters "iters", "limit", // and "max" have to be tuned to find all cycles in // a reasonable amount of time. Increasing "iters" // usually decreases execution time. When "iters" // is increased, "max" must usually be increased // (up to at most about 0x4000000). A good c value // to tune the parameters with is 17021 (where // there should be 258 cycles). For some larger // c values, "iters" must be set to 2 to find all // cycles. When "iters" is set to 0, every "twig" // of the tree in the range determined by "limit" // is checked. unsigned int limit=18000000; // must be a multiple of 6, should be as large as // possible relative to "max" to allow for cycles // having a constrained dynamic range. Increasing // "limit" increases the execution time. Cycles with // (K+L,K) values equal to continued-fraction convergents // of log(3)/log(2) are most likely to be missed if // the parameters haven't been set properly. unsigned int max=0x4000000; // maximum allowable value of first word of double- // word unsigned int outflag=0; // output flag (if set to 0, (L+K, K) values and // minima are output, otherwise attachment points // are output) int i; unsigned int first,acount,kount,attind,o,gomind,gop,numbc,noattind,oddind; unsigned int n,c,t,e,g,h,j,count,flag,oldlop,lodds,bigind,clkind; unsigned int index,z,lopind,lop,K[2],T[2],U[2],L[2],C[2],V[2],Y[2],Z[2],P[3]; unsigned int KP[2],MIN[2],itersp,limitp; for (j=0; j<10; j++) error[j]=0; if (cstart==(cstart/3)*3) { error[0]=1; goto zskip; } if (cstart==(cstart/2)*2) { error[0]=2; goto zskip; } if (cend==(cend/3)*3) { error[0]=3; goto zskip; } if (cend==(cend/2)*2) { error[0]=4; goto zskip; } if (cend>199999*5) { error[0]=5; goto zskip; } index=0; n=0; for (h=(unsigned int)cstart; h<=(unsigned int)cend; h+=2) { if (h==(h/3)*3) continue; cval[index]=h; index=index+1; if (index>=400) { error[0]=10; goto zskip; } } numbc=index; for (h=0; h<100*5; h++) bigcyc[h]=0; output[0]=0; output[1]=0; bigind=0; Z[0]=0; Z[1]=0; index=0; oddind=0; lopind=0; attind=0; clkind=0; for (c=cstart; c<=cend; c+=2) { if (c==(c/3)*3) continue; if ((c==31639)||(c==39409)||(c==71515)||(c==85105)||(c==169495)||(c==178825)) { itersp=0; limitp=24000000; } else { if (c==158195) { itersp=0; limitp=30000000; } else { if (c==185357) { itersp=0; limitp=60000000; } else { itersp=iters; limitp=limit; } } } error[1]=c; kount=0; gomind=0; noattind=0; C[0]=0; C[1]=c; count=0; z=0; if (c!=1) { factor[0]=c; count=1; for (i=1; i<17983; i++) { t=(unsigned int)table[i]; if (t>c) break; if (c==(c/t)*t) { factor[count]=t; count=count+1; } } } lop=0; for (i=3-(int)limitp; i<(int)limitp; i+=6) { K[1]=(unsigned int)i; error[2]=K[1]; if (i<0) // initial sequence value K[0]=0xffffffff; else K[0]=0; // // do jumps // /* for (h=0; h<itersp; h++) { add64(C, K); n=0; // clear count while ((K[1]&3)==0) { K[1]=(K[1]>>2)|(K[0]<<30); K[0]=(int)K[0]>>2; n=n+2; } if ((K[1]&1)==0) { K[1]=(K[1]>>1)|(K[0]<<31); K[0]=(int)K[0]>>1; n=n+1; } T[0]=K[0]; T[1]=K[1]; flag=0; if ((K[0]&0x80000000)!=0) { sub64(Z, K); flag=1; } for (j=0; j<n; j++) { if (K[0]>max) goto askip; L[0]=(K[0]<<1)|(K[1]>>31); L[1]=K[1]<<1; add64(L, K); } if (flag!=0) sub64(Z, K); L[0]=C[0]; L[1]=C[1]; sub64(K, L); K[1]=(L[1]>>1)|(L[0]<<31); K[0]=(int)L[0]>>1; if ((K[1]&1)==0) goto askip; } */ // // equivalent C64 assembly language // if (itersp>0) { t=jumps(K[0],K[1],itersp,c,max,output); if (t==0) goto askip; K[0]=output[0]; K[1]=output[1]; } // // check if primitive // T[0]=K[0]; T[1]=K[1]; if ((T[0]&0x80000000)!=0) sub64(Z, T); for (e=0; e<count; e++) { t=factor[e]; div64_32(T, U, t); mul64_32(U[0], U[1], t, P); if ((T[0]==P[1])&&(T[1]==P[2])) goto askip; } // // find cycle // /* L[0]=(K[0]<<1)|(K[1]>>31); L[1]=K[1]<<1; add64(L, K); add64(C, K); T[0]=K[0]; T[1]=K[1]; if ((T[0]&0x80000000)!=0) sub64(Z, T); if (T[0]>max) goto askip; while ((K[1]&3)==0) { K[1]=(K[1]>>2)|(K[0]<<30); K[0]=(int)K[0]>>2; } if ((K[1]&1)==0) { K[1]=(K[1]>>1)|(K[0]<<31); K[0]=(int)K[0]>>1; } // KP[0]=K[0]; KP[1]=K[1]; L[0]=(KP[0]<<1)|(KP[1]>>31); L[1]=KP[1]<<1; add64(L, KP); add64(C, KP); T[0]=KP[0]; T[1]=KP[1]; if ((T[0]&0x80000000)!=0) sub64(Z, T); if (T[0]>max) goto askip; while ((KP[1]&3)==0) { KP[1]=(KP[1]>>2)|(KP[0]<<30); KP[0]=(int)KP[0]>>2; } if ((KP[1]&1)==0) { KP[1]=(KP[1]>>1)|(KP[0]<<31); KP[0]=(int)KP[0]>>1; } // // begin loop // bloop:L[0]=(K[0]<<1)|(K[1]>>31); L[1]=K[1]<<1; add64(L, K); add64(C, K); T[0]=K[0]; T[1]=K[1]; if ((T[0]&0x80000000)!=0) sub64(Z, T); if (T[0]>max) goto askip; while ((K[1]&3)==0) { K[1]=(K[1]>>2)|(K[0]<<30); K[0]=(int)K[0]>>2; } if ((K[1]&1)==0) { K[1]=(K[1]>>1)|(K[0]<<31); K[0]=(int)K[0]>>1; } // L[0]=(KP[0]<<1)|(KP[1]>>31); L[1]=KP[1]<<1; add64(L, KP); add64(C, KP); while ((KP[1]&3)==0) { KP[1]=(KP[1]>>2)|(KP[0]<<30); KP[0]=(int)KP[0]>>2; } if ((KP[1]&1)==0) { KP[1]=(KP[1]>>1)|(KP[0]<<31); KP[0]=(int)KP[0]>>1; } L[0]=(KP[0]<<1)|(KP[1]>>31); L[1]=KP[1]<<1; add64(L, KP); add64(C, KP); T[0]=KP[0]; T[1]=KP[1]; if ((T[0]&0x80000000)!=0) sub64(Z, T); if (T[0]>max) goto askip; while ((KP[1]&3)==0) { KP[1]=(KP[1]>>2)|(KP[0]<<30); KP[0]=(int)KP[0]>>2; } if ((KP[1]&1)==0) { KP[1]=(KP[1]>>1)|(KP[0]<<31); KP[0]=(int)KP[0]>>1; } if ((K[0]!=KP[0])||(K[1]!=KP[1])) goto bloop; */ // // equivalent C64 assembly language // o=cycle(K[0],K[1],max,c,output); if (o==2) { error[0]=11; // goto zskip; goto askip; } if (o==0) goto askip; K[0]=output[0]; K[1]=output[1]; KP[0]=K[0]; KP[1]=K[1]; // // find attachment point // /* MIN[0]=K[0]; MIN[1]=K[1]; flag=0; L[0]=(K[0]<<1)|(K[1]>>31); L[1]=K[1]<<1; add64(L, K); add64(C, K); g=1; if ((K[1]&7)==0) { Y[0]=K[0]; Y[1]=K[1]; flag=1; } while ((K[1]&3)==0) { K[1]=(K[1]>>2)|(K[0]<<30); K[0]=(int)K[0]>>2; g=g+2; } if ((K[1]&1)==0) { K[1]=(K[1]>>1)|(K[0]<<31); K[0]=(int)K[0]>>1; g=g+1; } T[0]=K[0]; T[1]=K[1]; sub64(MIN, T); if ((T[0]&0x80000000)==0) { MIN[0]=K[0]; MIN[1]=K[1]; } o=1; while ((K[0]!=KP[0])||(K[1]!=KP[1])) { L[0]=(K[0]<<1)|(K[1]>>31); L[1]=K[1]<<1; add64(L, K); add64(C, K); g=g+1; if (((K[1]&7)==0)&&(flag==0)) { Y[0]=K[0]; Y[1]=K[1]; flag=1; } while ((K[1]&3)==0) { K[1]=(K[1]>>2)|(K[0]<<30); K[0]=(int)K[0]>>2; g=g+2; } if ((K[1]&1)==0) { K[1]=(K[1]>>1)|(K[0]<<31); K[0]=(int)K[0]>>1; g=g+1; } T[0]=K[0]; T[1]=K[1]; sub64(MIN, T); if ((T[0]&0x80000000)==0) { MIN[0]=K[0]; MIN[1]=K[1]; } o=o+1; } if (flag==0) goto askip; gop=(g<<16)|o; */ // // equivalent C64 assembly language (with additional check for cycles without // attachment points) // t=regen(KP[0],KP[1],output,c); MIN[0]=output[0]; MIN[1]=output[1]; gop=output[2]; Y[0]=output[3]; Y[1]=output[4]; g=gop>>16; o=gop&0xffff; if (t==0) { if (noattind==0) goto cjump; t=check(gop, MIN[0], MIN[1], noatt, noattind); if (t==0) goto askip; cjump: noatt[3*noattind]=gop; noatt[3*noattind+1]=MIN[0]; noatt[3*noattind+2]=MIN[1]; noattind=noattind+1; if (noattind>999) { error[0]=14; goto zskip; } oddout[4*oddind]=c; oddout[4*oddind+1]=((g-o)<<16)|o; oddout[4*oddind+2]=MIN[0]; oddout[4*oddind+3]=MIN[1]; oddind=oddind+1; if (oddind>999) { error[0]=13; goto zskip; } goto askip; } // // check for duplicate cycles // /* for (h=0; h<gomind; h++) { if (gop==gom[3*h]) { if ((MIN[0]==gom[3*h+1])&&(MIN[1]==gom[3*h+2])) { goto askip; } } } */ // // equivalent C64 assembly language // if (gomind==0) goto bjump; t=check(gop, MIN[0], MIN[1], gom, gomind); if (t==0) goto askip; bjump: gom[3*gomind]=gop; gom[3*gomind+1]=MIN[0]; gom[3*gomind+2]=MIN[1]; gomind=gomind+1; if (gomind>9999) { error[0]=6; goto zskip; } if (outflag==0) { clkout[4*clkind]=c; clkout[4*clkind+1]=((g-o)<<16)|o; clkout[4*clkind+2]=MIN[0]; clkout[4*clkind+3]=MIN[1]; clkind=clkind+1; if (clkind>9999) { error[0]=12; goto zskip; } goto askip; } // // new cycle // kount=kount+1; oldlop=lop; lodds=0; acount=0; flag=0; T[0]=Y[0]; T[1]=Y[1]; V[0]=T[0]; V[1]=T[1]; // // begin loop // aloop:first=0; while ((T[1]&3)==0) { T[1]=(T[1]>>2)|(T[0]<<30); T[0]=(int)T[0]>>2; if ((T[1]&1)==1) goto qskip; if (first==0) { acount=acount+1; first=1; } U[0]=T[0]; U[1]=T[1]; if ((U[0]&0x80000000)!=0) sub64(Z, U); if ((U[0]!=0)||((U[1]&0x80000000)!=0)) { flag=1; bigatt[3*attind]=c; bigatt[3*attind+1]=T[0]; bigatt[3*attind+2]=T[1]; attind=attind+1; if (attind>399) { error[0]=7; goto zskip; } } out[index]=T[1]; cyc[index]=z; index=index+1; if (index>89999) { error[0]=8; goto zskip; } lop=lop+1; if ((T[0]==V[0])&&(T[1]==V[1])) { acount=acount-1; goto rskip; } } if ((T[1]&1)==0) { T[1]=(T[1]>>1)|(T[0]<<31); T[0]=(int)T[0]>>1; } qskip:lodds=lodds+1; L[0]=(T[0]<<1)|(T[1]>>31); L[1]=T[1]<<1; add64(L, T); add64(C, T); if ((T[0]!=V[0])||(T[1]!=V[1])) goto aloop; // // save big attachment points // rskip:if (flag!=0) { bigcyc[bigind*5]=c; bigcyc[bigind*5+1]=lop-oldlop; bigcyc[bigind*5+2]=g-2*lodds; bigcyc[bigind*5+3]=lodds; bigcyc[bigind*5+4]=acount; bigind=bigind+1; if (bigind>199) { error[0]=9; goto zskip; } } z=z+1; askip:n=n+1; } if (outflag!=0) { lopcnt[lopind]=lop; lopind=lopind+1; } } error[2]=index; error[3]=lopind; error[4]=numbc; error[5]=bigind; error[6]=attind; error[7]=clkind; error[8]=oddind; zskip: return(0); }