﻿ /*******************************
```/******************************************************************************/
/*									      */
/*  FIND THE MINIMUM ELEMENT IN A CYCLE 				      */
/*  07/25/10 (dkc)							      */
/*									      */
/*  This C program finds the minimum element in a cycle.  c is set to 1 or -1.*/
/*  Potential cycles are in limbs in S of a least-residue tree.  n is the     */
/*  number of odd elements in the cycle and l is the length of the cycle.     */
/*									      */
/*  This program is for use on the C64. 				      */
/*									      */
/******************************************************************************/
#include <math.h>
void rshiftn(unsigned int *a, unsigned int *b, unsigned int shift, unsigned int n);
void addn(unsigned int *a, unsigned int *b, unsigned int n);
void copyn(unsigned int *a, unsigned int *b, unsigned int n);
void setn(unsigned int *a, unsigned int b, unsigned int n);
void negn(unsigned int *a, unsigned int n);
void mult3(unsigned int *a, unsigned int n);
far unsigned int error[6];	// flags
far unsigned int MAX[2];	// maximum odd element
far unsigned int MIN[2];	// minimum odd element
far unsigned int H[2];		// greater than order/2, less than order
far unsigned int sv[158];	// parity vector
far double pv[158];
far unsigned int R[257*2];	// limbs in S
far unsigned int O[100*2];	// odd elements of a limb in S
far unsigned int ab[100*2]={	// a and b values
0, 1, 0, 2, 1, 2, 1, 3, 2, 3,
2, 4, 3, 4, 4, 4, 4, 5, 5, 5,
5, 6, 6, 6, 7, 6, 7, 7, 8, 7,
8, 8, 9, 8, 9, 9, 10, 9, 11, 9,
11, 10, 12, 10, 12, 11, 13, 11, 14, 11,
14, 12, 15, 12, 15, 13, 16, 13, 16, 14,
17, 14, 18, 14, 18, 15, 19, 15, 19, 16,
20, 16, 21, 16, 21, 17, 22, 17, 22, 18,
23, 18, 23, 19, 24, 19, 25, 19, 25, 20,
26, 20, 26, 21, 27, 21, 28, 21, 28, 22,
29, 22, 29, 23, 30, 23, 31, 23, 31, 24,
32, 24, 32, 25, 33, 25, 33, 26, 34, 26,
35, 26, 35, 27, 36, 27, 36, 28, 37, 28,
38, 28, 38, 29, 39, 29, 39, 30, 40, 30,
40, 31, 41, 31, 42, 31, 42, 32, 43, 32,
43, 33, 44, 33, 45, 33, 45, 34, 46, 34,
46, 35, 47, 35, 47, 36, 48, 36, 49, 36,
49, 37, 50, 37, 50, 38, 51, 38, 52, 38,
52, 39, 53, 39, 53, 40, 54, 40, 54, 41,
55, 41, 56, 41, 56, 42, 57, 42, 57, 43};
int main () {
//
unsigned int len=53;			// specified limb length
unsigned int sflag=1;			// limb in S flag
unsigned int shift=1;			// right-shift amount of order
unsigned int delta=20000;		// S increment (usually 2)
unsigned int J[2]={0x00006000, 0x00000000}; // order
unsigned int I[2]={0x00003000, 0x00000000}; // order/2
unsigned int K[2]={0x00002000, 0x00000000}; // order/3
unsigned int C[2]={0x00000000, 0x00000001}; // c
//unsigned int C[2]={0xffffffff, 0xffffffff}; // c
unsigned int maxiters=1000000;		// maximum number of limbs in S
unsigned int m=2;			// number of words
//
unsigned int G[2],T[2],length,offset,temp,saveh;
unsigned int h,i,j,k,l,n,a,b,oldg,index,iters,count;
double max,min;
rshiftn(J, J, shift, m);		// right-shift order
rshiftn(I, I, shift, m);		// right-shift order/2
rshiftn(K, K, shift, m);		// right-shift order/3
setn(T, 2, m);				// load 2
setn(MAX, 0, m);			// clear maximum odd element
setn(MIN, 0, m);			// clear minimum odd element
error[0]=0;				// clear error and flag array
error[1]=0;
error[2]=0;
error[3]=0;
error[4]=0;
error[5]=0;
setn(O, 0, 100*m);			// clear output array
for (i=0; i<158; i++) { 		// clear parity vector
sv[i]=0xffffffff;
pv[i]=0.0;
}
iters=0;				// clear limb count
for (i=0; i<100; i++) {
length=3*ab[2*i]+2*ab[2*i+1];	// length of limb
if (length!=len)			// check for specified length
continue;
l=2*ab[2*i]+ab[2*i+1]+1;		// length of cycle
n=ab[2*i]+ab[2*i+1]; 		// number of odd elements in cycle
offset=0;				// set index offsets
if (length==4)			// l=3, n=2, shift=18, delta=2
offset=0;
if (length==7)			// l=5, n=3, shift=18, delta=2
offset=0;
if (length==9)			// l=6, n=4, shift=18, delta=2
offset=0;
if (length==12)			// l=8, n=5, shift=18, delta=2
offset=0;
if (length==14)			// l=9, n=6, shift=18, delta=2
offset=0;
if (length==17)			// l=11, n=7, shift=18, delta=2
offset=0; 			// or 5,8
if (length==20)			// l=13, n=8, shift=18, delta=2
offset=5; 			// or 10, not 0
if (length==22)			// l=14, n=9, shift=18, delta=2
offset=11;			// or 5,8, not 0
if (length==25)			// l=16, n=10, shift=18, delta=2
offset=0; 			// or 5,8,13
if (length==27)			// l=17, n=11, shift=18, delta=2
offset=11;			// or 5,8, not 0,14
if (length==30)			// l=19, n=12, shift=16, delta=2
offset=0; 			// or 5,8,13,16
if (length==33)			// l=21, n=13, shift=14, delta=2
offset=5; 			// or 10,18 not 0,13
if (length==35)			// l=22, n=14, shift=13, delta=2
offset=8; 			// or 5,11,16,19, not 0
if (length==38)			// l=24, n=15, shift=13, delta=2
offset=0; 			// or 5,8,13,16,21
if (length==40)			// l=25, n=16, shift=12, delta=2
offset=19;// for 5,16, 3*MIN!>MAX // or 5,16, not 0,8,11,22
if (length==43)			// l=27, n=17, shift=12, delta=2
offset=0; 			// or 5,8,13,16,21,24
if (length==45)			// l=28, n=18, shift=12, delta=2
offset=5; // for 5,19 3*MIN!>MAX	// or 19, not 0,8,11,14,22,25
if (length==48)			// l=30, n=19, shift=11, delta=2
offset=8; 			// or 5,13,16,27 not 0,19
if (length==51)			// l=32, n=20, shift=1, delta=20000
offset=5; 			// or 13,21,29, not 0,8,16,24
if (length==53)			// l=33, n=21, shift=1, delta=20000
offset=5; 			// or 8,11,16,19,22,27, not 0,30 ???
if (length==56)			// l=35, n=22, shift=1, delta=20000
offset=5; 			// or 8,13,16,21,24,29,32, not 0 ???
//
// Note: Offsets haven't been determined for lengths greater than 56.
//
//
//  compute parity vector
//
for (j=1; j<=l; j++) {
a=j*n;
if (a==((a/l)*l)) 		// a=(j*n)/l
a=a/l;
else
a=(a/l)+1;
b=(j-1)*n;
if (b==((b/l)*l)) 		// b=((j-1)*n)/l
b=b/l;
else
b=(b/l)+1;
k=a-b;				// parity value
temp=j+offset;			// store value using circular addressing
if (temp>l)
temp=temp-l;
sv[temp-1]=k;
}
//
// check parity vector
//
pv[1]=1.0;
for (j=1; j<l; j++) {
if (sv[j]==1)
pv[j+1]=1.5*pv[j];
else
pv[j+1]=0.5*pv[j];
}
h=1;
max=0.0;
min=1000000;
for (j=1; j<l; j++) {		// find maximum and minimum
if (sv[j]==1) {
if (pv[j]>max) {
max=pv[j];
h=j;
}
if (pv[j]<min)
min=pv[j];
}
}
if (pv[l-1]<max)
error[0]=h;
if (pv[l-1]>2.0)
error[4]=1;
if (3.0*min<max)
error[4]=2;
if (2.0*min<max)
error[5]=1;			// okay when last two s.v. values are 1, 1
//
// find limb in S having given sequence vector
//
copyn(I, H, m);			// save starting element of limb
aloop:
copyn(H, G, m);			// load starting element of limb
index=0;				// clear index
oldg=0;
copyn(G, R, m);			// store limb element
count=1;
error[0]=0;
for (j=0; j<(length-1); j++) {
if ((G[m-1]&1)==0) {		// check for even element
if (oldg==0) {		// check sequence
if (sv[index]!=1)
}
else {
if (sv[index]!=0)
}
oldg=1;
rshiftn(G, G, 1, m);	// halve element
index=index+1;		// increment index
R[2*count]=G[0];		// save element
R[2*count+1]=G[1];
count=count+1;
}
else { 			// odd element
mult3(G, m);		// compute next even element
copyn(J, T, m);		// load order
addn(G, T, m);		// even element minus order
if (sflag!=0) {
if ((T[0]&0x80000000)==0)   // if non-negative, continue
}
else {
if ((T[0]&0x80000000)==0)   // if non-negative, set flag
error[0]=1;
}
oldg=0;
R[2*count]=G[0];		// save element of limb
R[2*count+1]=G[1];
count=count+1;
}
}
if ((G[m-1]&1)==1) {		// check for odd element
copyn(K, T, m);		// load order/3
addn(G, T, m); 		// odd element minus order/3
if ((T[0]&0x80000000)!=0)	// if negative, continue
h=0;
setn(MAX, 0, m);
setn(MIN, 1, m);
negn(MIN, m);
MIN[0]=MIN[0]&0x7fffffff;
for (j=0; j<count; j++) {	// save odd elements of limb
if ((R[m*j+(m-1)]&1)==1) {
copyn(R+m*j, O+m*h, m);
copyn(R+m*j, T, m);	// find maximum
negn(T, m);
if ((T[0]&0x80000000)!=0) {
copyn(R+m*j, MAX, m);
saveh=h;
}
copyn(R+m*j, T, m);	// find minimum
negn(T, m);
if ((T[0]&0x80000000)==0)
copyn(R+m*j, MIN, m);
h=h+1;
}
}
if ((saveh+1)!=h)		// check if last is largest
error[1]=1;
copyn(MIN, T, m);		// check if 2*MIN>MAX
copyn(MAX, G, m);
negn(G, m);
if ((G[0]&0x80000000)!=0)
error[3]=1;
copyn(MIN, T, m);		// check if 3*MIN>MAX
copyn(MAX, G, m);
negn(G, m);
if ((G[0]&0x80000000)!=0)
error[3]=0xffffffff;
iters=iters+1; 		// increment limb count
error[2]=iters;		// save limb count
if (iters==maxiters)
goto zskip;
}