-/**************************************************************
- *
- * giants.c
- *
- * Library for large-integer arithmetic.
- *
- * The large-gcd implementation is due to J. P. Buhler.
- * Special mod routines use ideas of R. McIntosh.
- * Contributions from G. Woltman, A. Powell acknowledged.
- *
- * Updates:
- * 18 Jul 99 REC Added routine fer_mod(), for use when Fermat
- giant itself is available.
- * 17 Jul 99 REC Fixed sign bug in fermatmod()
- * 17 Apr 99 REC Fixed various comment/line wraps
- * 25 Mar 99 REC G. Woltman/A. Powell fixes Karat. routines
- * 05 Mar 99 REC Moved invaux, binvaux giants to stack
- * 05 Mar 99 REC Moved gread/gwrite giants to stack
- * 05 Mar 99 REC No static on cur_den, cur_recip (A. Powell)
- * 28 Feb 99 REC Error detection added atop newgiant().
- * 27 Feb 99 REC Reduced wasted work in addsignal().
- * 27 Feb 99 REC Reduced wasted work in FFTmulg().
- * 19 Feb 99 REC Generalized iaddg() per R. Mcintosh.
- * 2 Feb 99 REC Fixed comments.
- * 6 Dec 98 REC Fixed yet another Karatsuba glitch.
- * 1 Dec 98 REC Fixed errant case of addg().
- * 28 Nov 98 REC Installed A. Powell's (correct) variant of
- Karatsuba multiply.
- * 15 May 98 REC Modified gwrite() to handle huge integers.
- * 13 May 98 REC Changed to static stack declarations
- * 11 May 98 REC Installed Karatsuba multiply, to handle
- * medregion 'twixt grammar- and FFT-multiply.
- * 1 May 98 JF gshifts now handle bits < 0 correctly.
- * 30 Apr 98 JF 68k assembler code removed,
- * stack giant size now invariant and based
- * on first call of newgiant(),
- * stack memory leaks fixed.
- * 29 Apr 98 JF function prototyes cleaned up,
- * GCD no longer uses personal stack,
- * optimized shifts for bits%16 == 0.
- * 27 Apr 98 JF scratch giants now replaced with stack
- * 20 Apr 98 JF grammarsquareg fixed for asize == 0.
- * scratch giants now static.
- * 29 Jan 98 JF Corrected out-of-range errors in
- * mersennemod and fermatmod.
- * 23 Dec 97 REC Sped up divide routines via split-shift.
- * 18 Nov 97 JF Improved mersennemod, fermatmod.
- * 9 Nov 97 JF Sped up grammarsquareg.
- * 20 May 97 RDW Fixed Win32 compiler warnings.
- * 18 May 97 REC Installed new, fast divide.
- * 17 May 97 REC Reduced memory for FFT multiply.
- * 26 Apr 97 REC Creation.
- *
- * c. 1997,1998 Perfectly Scientific, Inc.
- * All Rights Reserved.
- *
- **************************************************************/
-
-
-/* Include Files. */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-#include "giants.h"
-
-
-/* Compiler options. */
-
-#ifdef _WIN32
-#pragma warning( disable : 4127 4706 ) /* disable conditional is constant warning */
-#endif
-
-
-/* Global variables. */
-
-int error = 0;
-int mulmode = AUTO_MUL;
-int cur_prec = 0;
-int cur_shift = 0;
-static int cur_stack_size = 0;
-static int cur_stack_elem = 0;
-static int stack_glen = 0;
-static giant *stack;
-giant cur_den = NULL,
- cur_recip = NULL;
-int current_max_size = 0,
- cur_run = 0;
-double * sinCos=NULL;
-int checkFFTerror = 0;
-double maxFFTerror;
-static giant u0=NULL, u1=NULL, v0=NULL, v1=NULL;
-static double *z = NULL,
- *z2 = NULL;
-
-/* stack handling functions. */
-static giant popg(void);
-static void pushg(int);
-
-
-/* Private function prototypes. */
-
-int gerr(void);
-double gfloor(double);
-int radixdiv(int, int, giant);
-void columnwrite(FILE *, short *, char *, short, int);
-
-void normal_addg(giant, giant);
-void normal_subg(giant, giant);
-void reverse_subg(giant, giant);
-int binvaux(giant, giant);
-int invaux(giant, giant);
-int allzeros(int, int, giant);
-void auxmulg(giant a, giant b);
-void karatmulg(giant a, giant b);
-void karatsquareg(giant b);
-void grammarmulg(giant a, giant b);
-void grammarsquareg(giant b);
-
-int lpt(int, int *);
-void addsignal(giant, double *, int);
-void FFTsquareg(giant x);
-void FFTmulg(giant y, giant x);
-void scramble_real();
-void fft_real_to_hermitian(double *z, int n);
-void fftinv_hermitian_to_real(double *z, int n);
-void mul_hermitian(double *a, double *b, int n);
-void square_hermitian(double *b, int n);
-void giant_to_double(giant x, int sizex, double *z, int L);
-void gswap(giant *, giant *);
-void onestep(giant, giant, gmatrix);
-void mulvM(gmatrix, giant, giant);
-void mulmM(gmatrix, gmatrix);
-void writeM(gmatrix);
-static void punch(giant, gmatrix);
-static void dotproduct(giant, giant, giant, giant);
-void fix(giant *, giant *);
-void hgcd(int, giant, giant, gmatrix);
-void shgcd(int, int, gmatrix);
-
-
-
-/**************************************************************
- *
- * Functions
- *
- **************************************************************/
-
-
-/**************************************************************
- *
- * Initialization and utility functions
- *
- **************************************************************/
-
-double
-gfloor(
- double f
-)
-{
- return floor(f);
-}
-
-
-void
-init_sinCos(
- int n
-)
-{
- int j;
- double e = TWOPI/n;
-
- if (n<=cur_run)
- return;
- cur_run = n;
- if (sinCos)
- free(sinCos);
- sinCos = (double *)malloc(sizeof(double)*(1+(n>>2)));
- for (j=0;j<=(n>>2);j++)
- {
- sinCos[j] = sin(e*j);
- }
-}
-
-
-double
-s_sin(
- int n
-)
-{
- int seg = n/(cur_run>>2);
-
- switch (seg)
- {
- case 0: return(sinCos[n]);
- case 1: return(sinCos[(cur_run>>1)-n]);
- case 2: return(-sinCos[n-(cur_run>>1)]);
- case 3: return(-sinCos[cur_run-n]);
- }
- return 0;
-}
-
-
-double
-s_cos(
- int n
-)
-{
- int quart = (cur_run>>2);
-
- if (n < quart)
- return(s_sin(n+quart));
- return(-s_sin(n-quart));
-}
-
-
-int
-gerr(void)
-{
- return(error);
-}
-
-
-giant
-popg (
- void
-)
-{
- int i;
-
- if (current_max_size <= 0) current_max_size = MAX_SHORTS;
-
- if (cur_stack_size == 0) {
-/* Initialize the stack if we're just starting out.
- * Note that all stack giants will be whatever current_max_size is
- * when newgiant() is first called. */
- cur_stack_size = STACK_GROW;
- stack = (giant *) malloc (cur_stack_size * sizeof(giant));
- for(i = 0; i < STACK_GROW; i++)
- stack[i] = NULL;
- if (stack_glen == 0) stack_glen = current_max_size;
- } else if (cur_stack_elem >= cur_stack_size) {
-/* Expand the stack if we need to. */
- i = cur_stack_size;
- cur_stack_size += STACK_GROW;
- stack = (giant *) realloc (stack,cur_stack_size * sizeof(giant));
- for (; i < cur_stack_size; i++)
- stack[i] = NULL;
- } else if (cur_stack_elem < cur_stack_size - 2*STACK_GROW) {
-/* Prune the stack if it's too big. Disabled, so the stack can only expand */
- /* cur_stack_size -= STACK_GROW;
- for (i = cur_stack_size - STACK_GROW; i < cur_stack_size; i++)
- free(stack[i]);
- stack = (giant *) realloc (stack,cur_stack_size * sizeof(giant)); */
- }
-
-/* Malloc our giant. */
- if (stack[cur_stack_elem] == NULL)
- stack[cur_stack_elem] = malloc(stack_glen*sizeof(short)+sizeof(int));
- stack[cur_stack_elem]->sign = 0;
-
- return(stack[cur_stack_elem++]);
-}
-
-
-void
-pushg (
- int a
-)
-{
- if (a < 0) return;
- cur_stack_elem -= a;
- if (cur_stack_elem < 0) cur_stack_elem = 0;
-}
-
-
-giant
-newgiant(
- int numshorts
-)
-{
- int size;
- giant thegiant;
-
- if (numshorts > MAX_SHORTS) {
- fprintf(stderr, "Requested giant too big.\n");
- fflush(stderr);
- }
- if (numshorts<=0)
- numshorts = MAX_SHORTS;
- size = numshorts*sizeof(short)+sizeof(int);
- thegiant = (giant)malloc(size);
- thegiant->sign = 0;
-
- if (newmin(2*numshorts,MAX_SHORTS) > current_max_size)
- current_max_size = newmin(2*numshorts,MAX_SHORTS);
-
-/* If newgiant() is being called for the first time, set the
- * size of the stack giants. */
- if (stack_glen == 0) stack_glen = current_max_size;
-
- return(thegiant);
-}
-
-
-gmatrix
-newgmatrix(
- void
-)
-/* Allocates space for a gmatrix struct, but does not
- * allocate space for the giants. */
-{
- return((gmatrix) malloc (4*sizeof(giant)));
-}
-
-int
-bitlen(
- giant n
-)
-{
- int b = 16, c = 1<<15, w;
-
- if (isZero(n))
- return(0);
- w = n->n[abs(n->sign) - 1];
- while ((w&c) == 0)
- {
- b--;
- c >>= 1;
- }
- return (16*(abs(n->sign)-1) + b);
-}
-
-
-int
-bitval(
- giant n,
- int pos
-)
-{
- int i = abs(pos)>>4, c = 1 << (pos&15);
-
- return ((n->n[i]) & c);
-}
-
-
-int
-isone(
- giant g
-)
-{
- return((g->sign==1)&&(g->n[0]==1));
-}
-
-
-int isZero(
- giant thegiant
-)
-/* Returns TR if thegiant == 0. */
-{
- register int count;
- int length = abs(thegiant->sign);
- register unsigned short * numpointer = thegiant->n;
-
- if (length)
- {
- for(count = 0; count<length; ++count,++numpointer)
- {
- if (*numpointer != 0 )
- return(FA);
- }
- }
- return(TR);
-}
-
-
-void
-gtog(
- giant srcgiant,
- giant destgiant
-)
-/* destgiant becomes equal to srcgiant. */
-{
- int numbytes = sizeof(int) + abs(srcgiant->sign)*sizeof(short);
-
- memcpy((char *)destgiant,(char *)srcgiant,numbytes);
-}
-
-
-void
-itog(
- int i,
- giant g
-)
-/* The giant g becomes set to the integer value i. */
-{
- unsigned int j = abs(i);
-
- if (i==0)
- {
- g->sign = 0;
- g->n[0] = 0;
- return;
- }
- g->n[0] = (unsigned short)(j & 0xFFFF);
- j >>= 16;
- if (j)
- {
- g->n[1] = (unsigned short)j;
- g->sign = 2;
- }
- else
- {
- g->sign = 1;
- }
- if (i<0)
- g->sign = -(g->sign);
-}
-
-
-signed int
-gtoi(
- giant x
-)
-/* Calculate the value of an int-sized giant NOT exceeding 31 bits. */
-{
- register int size = abs(x->sign);
- register int sign = (x->sign < 0) ? -1 : 1;
-
- switch(size)
- {
- case 0:
- break;
- case 1:
- return sign * x->n[0];
- case 2:
- return sign * (x->n[0]+((x->n[1])<<16));
- default:
- fprintf(stderr,"Giant too large for gtoi\n");
- break;
- }
- return 0;
-}
-
-
-int
-gsign(
- giant g
-)
-/* Returns the sign of g. */
-{
- if (isZero(g))
- return(0);
- if (g->sign >0)
- return(1);
- return(-1);
-}
-
-
-#if 0
-int gcompg(a,b)
-/* Returns -1,0,1 if a<b, a=b, a>b, respectively. */
- giant a,b;
-{
- int size = abs(a->sign);
-
- if(isZero(a)) size = 0;
- if (size == 0) {
- if (isZero(b)) return(0); else return(-gsign(b));
- }
-
- if (b->sign == 0) return(gsign(a));
- if (gsign(a)!=gsign(b)) return(gsign(a));
- if (size>abs(b->sign)) return(gsign(a));
- if (size<abs(b->sign)) return(-gsign(a));
-
- do {
- --size;
- if (a->n[size] > b->n[size]) return(gsign(a));
- if (a->n[size] < b->n[size]) return(-gsign(a));
- } while(size>0);
-
- return(0);
-}
-#else
-
-int
-gcompg(
- giant a,
- giant b
-)
-/* Returns -1,0,1 if a<b, a=b, a>b, respectively. */
-{
- int sa = a->sign, j, sb = b->sign, va, vb, sgn;
-
- if(sa > sb)
- return(1);
- if(sa < sb)
- return(-1);
- if(sa < 0)
- {
- sa = -sa; /* Take absolute value of sa. */
- sgn = -1;
- }
- else
- {
- sgn = 1;
- }
- for(j = sa-1; j >= 0; j--)
- {
- va = a->n[j];
- vb = b->n[j];
- if (va > vb)
- return(sgn);
- if (va < vb)
- return(-sgn);
- }
- return(0);
-}
-#endif
-
-
-void
-setmulmode(
- int mode
-)
-{
- mulmode = mode;
-}
-
-
-/**************************************************************
- *
- * Private I/O Functions
- *
- **************************************************************/
-
-
-int
-radixdiv(
- int base,
- int divisor,
- giant thegiant
-)
-/* Divides giant of arbitrary base by divisor.
- * Returns remainder. Used by idivg and gread. */
-{
- int first = TR;
- int finalsize = abs(thegiant->sign);
- int j = finalsize-1;
- unsigned short *digitpointer=&thegiant->n[j];
- unsigned int num,rem=0;
-
- if (divisor == 0)
- {
- error = DIVIDEBYZERO;
- exit(error);
- }
-
- while (j>=0)
- {
- num=rem*base + *digitpointer;
- *digitpointer = (unsigned short)(num/divisor);
- if (first)
- {
- if (*digitpointer == 0)
- --finalsize;
- else
- first = FA;
- }
- rem = num % divisor;
- --digitpointer;
- --j;
- }
-
- if ((divisor<0) ^ (thegiant->sign<0))
- finalsize=-finalsize;
- thegiant->sign=finalsize;
- return(rem);
-}
-
-
-void
-columnwrite(
- FILE *filepointer,
- short *column,
- char *format,
- short arg,
- int newlines
-)
-/* Used by gwriteln. */
-{
- char outstring[10];
- short i;
-
- sprintf(outstring,format,arg);
- for (i=0; outstring[i]!=0; ++i)
- {
- if (newlines)
- {
- if (*column >= COLUMNWIDTH)
- {
- fputs("\\\n",filepointer);
- *column = 0;
- }
- }
- fputc(outstring[i],filepointer);
- ++*column;
- }
-}
-
-
-void
-gwrite(
- giant thegiant,
- FILE *filepointer,
- int newlines
-)
-/* Outputs thegiant to filepointer. Output is terminated by a newline. */
-{
- short column;
- unsigned int i;
- unsigned short *numpointer;
- giant garbagegiant, basetengrand;
-
- basetengrand = popg();
- garbagegiant = popg();
-
- if (isZero(thegiant))
- {
- fputs("0",filepointer);
- }
- else
- {
- numpointer = basetengrand->n;
- gtog(thegiant,garbagegiant);
-
- basetengrand->sign = 0;
- do
- {
- *numpointer = (unsigned short)idivg(10000,garbagegiant);
- ++numpointer;
- if (++basetengrand->sign >= current_max_size)
- {
- error = OVFLOW;
- exit(error);
- }
- } while (!isZero(garbagegiant));
-
- if (!error)
- {
- i = basetengrand->sign-1;
- column = 0;
- if (thegiant->sign<0 && basetengrand->n[i]!=0)
- columnwrite(filepointer,&column,"-",0, newlines);
- columnwrite(filepointer,&column,"%d",basetengrand->n[i],newlines);
- for( ; i>0; )
- {
- --i;
- columnwrite(filepointer,&column,"%04d",basetengrand->n[i],newlines);
- }
- }
- }
- pushg(2);
-}
-
-
-void
-gwriteln(
- giant theg,
- FILE *filepointer
-)
-{
- gwrite(theg, filepointer, 1);
- fputc('\n',filepointer);
-}
-
-
-void
-gread(
- giant theg,
- FILE *filepointer
-)
-{
- char currentchar;
- int isneg,size,backslash=FA,numdigits=0;
- unsigned short *numpointer;
- giant basetenthousand;
- static char *inbuf = NULL;
-
- basetenthousand = popg();
- if (inbuf == NULL)
- inbuf = (char*)malloc(MAX_DIGITS);
-
- currentchar = (char)fgetc(filepointer);
- if (currentchar=='-')
- {
- isneg=TR;
- }
- else
- {
- isneg=FA;
- if (currentchar!='+')
- ungetc(currentchar,filepointer);
- }
-
- do
- {
- currentchar = (char)fgetc(filepointer);
- if ((currentchar>='0') && (currentchar<='9'))
- {
- inbuf[numdigits]=currentchar;
- if(++numdigits==MAX_DIGITS)
- break;
- backslash=FA;
- }
- else
- {
- if (currentchar=='\\')
- backslash=TR;
- }
- } while(((currentchar!=' ') && (currentchar!='\n') &&
- (currentchar!='\t')) || (backslash) );
- if (numdigits)
- {
- size = 0;
- do
- {
- inbuf[numdigits] = 0;
- numdigits-=4;
- if (numdigits<0)
- numdigits=0;
- basetenthousand->n[size] = (unsigned short)strtol(&inbuf[numdigits],NULL,10);
- ++size;
- } while (numdigits>0);
-
- basetenthousand->sign = size;
- theg->sign = 0;
- numpointer = theg->n;
- do
- {
- *numpointer = (unsigned short)
- radixdiv(10000,1<<(8*sizeof(short)),basetenthousand);
- ++numpointer;
- if (++theg->sign >= current_max_size)
- {
- error = OVFLOW;
- exit(error);
- }
- } while (!isZero(basetenthousand));
-
- if (isneg)
- theg->sign = -theg->sign;
- }
- pushg(1);
-}
-
-
-
-/**************************************************************
- *
- * Private Math Functions
- *
- **************************************************************/
-
-
-void
-negg(
- giant g
-)
-/* g becomes -g. */
-{
- g->sign = -g->sign;
-}
-
-
-void
-absg(
- giant g
-)
-{
- /* g becomes the absolute value of g. */
- if (g->sign <0)
- g->sign=-g->sign;
-}
-
-
-void
-iaddg(
- int i,
- giant g
-)
-/* Giant g becomes g + (int)i. */
-{
- int w,j=0,carry = 0, size = abs(g->sign);
- giant tmp;
-
- if (isZero(g))
- {
- itog(i,g);
- }
- else if(g->sign < 0) {
- tmp = popg();
- itog(i, tmp);
- addg(tmp, g);
- pushg(1);
- return;
- }
- else
- {
- w = g->n[0]+i;
- do
- {
- g->n[j] = (unsigned short) (w & 65535L);
- carry = w >> 16;
- w = g->n[++j]+carry;
- } while ((carry!=0) && (j<size));
- }
- if (carry)
- {
- ++g->sign;
- g->n[size] = (unsigned short)carry;
- }
-}
-
-
-/* New subtract routines.
- The basic subtract "subg()" uses the following logic table:
-
- a b if(b > a) if(a > b)
-
- + + b := b - a b := -(a - b)
- - + b := b + (-a) N.A.
- + - N.A. b := -((-b) + a)
- - - b := (-a) - (-b) b := -((-b) - (-a))
-
- The basic addition routine "addg()" uses:
-
- a b if(b > -a) if(-a > b)
-
- + + b := b + a N.A.
- - + b := b - (-a) b := -((-a) - b)
- + - b := a - (-b) b := -((-b) - a)
- - - N.A. b := -((-b) + (-a))
-
- In this way, internal routines "normal_addg," "normal_subg,"
- and "reverse_subg;" each of which assumes non-negative
- operands and a non-negative result, are now used for greater
- efficiency.
- */
-
-void
-normal_addg(
- giant a,
- giant b
-)
-/* b := a + b, both a,b assumed non-negative. */
-{
- int carry = 0;
- int asize = a->sign, bsize = b->sign;
- long k;
- int j=0;
- unsigned short *aptr = a->n, *bptr = b->n;
-
- if (asize < bsize)
- {
- for (j=0; j<asize; j++)
- {
- k = *aptr++ + *bptr + carry;
- carry = 0;
- if (k >= 65536L)
- {
- k -= 65536L;
- ++carry;
- }
- *bptr++ = (unsigned short)k;
- }
- for (j=asize; j<bsize; j++)
- {
- k = *bptr + carry;
- carry = 0;
- if (k >= 65536L)
- {
- k -= 65536L;
- ++carry;
- }
- *bptr++ = (unsigned short)k;
- }
- }
- else
- {
- for (j=0; j<bsize; j++)
- {
- k = *aptr++ + *bptr + carry;
- carry = 0;
- if (k >= 65536L)
- {
- k -= 65536L;
- ++carry;
- }
- *bptr++ = (unsigned short)k;
- }
- for (j=bsize; j<asize; j++)
- {
- k = *aptr++ + carry;
- carry = 0;
- if (k >= 65536L)
- {
- k -= 65536L;
- ++carry;
- }
- *bptr++ = (unsigned short)k;
- }
- }
- if (carry)
- {
- *bptr = 1; ++j;
- }
- b->sign = j;
-}
-
-
-void
-normal_subg(
- giant a,
- giant b
-)
-/* b := b - a; requires b, a non-negative and b >= a. */
-{
- int j, size = b->sign;
- unsigned int k;
-
- if (a->sign == 0)
- return;
-
- k = 0;
- for (j=0; j<a->sign; ++j)
- {
- k += 0xffff - a->n[j] + b->n[j];
- b->n[j] = (unsigned short)(k & 0xffff);
- k >>= 16;
- }
- for (j=a->sign; j<size; ++j)
- {
- k += 0xffff + b->n[j];
- b->n[j] = (unsigned short)(k & 0xffff);
- k >>= 16;
- }
-
- if (b->n[0] == 0xffff)
- iaddg(1,b);
- else
- ++b->n[0];
-
- while ((size-- > 0) && (b->n[size]==0));
-
- b->sign = (b->n[size]==0) ? 0 : size+1;
-}
-
-
-void
-reverse_subg(
- giant a,
- giant b
-)
-/* b := a - b; requires b, a non-negative and a >= b. */
-{
- int j, size = a->sign;
- unsigned int k;
-
- k = 0;
- for (j=0; j<b->sign; ++j)
- {
- k += 0xffff - b->n[j] + a->n[j];
- b->n[j] = (unsigned short)(k & 0xffff);
- k >>= 16;
- }
- for (j=b->sign; j<size; ++j)
- {
- k += 0xffff + a->n[j];
- b->n[j] = (unsigned short)(k & 0xffff);
- k >>= 16;
- }
-
- b->sign = size; /* REC, 21 Apr 1996. */
- if (b->n[0] == 0xffff)
- iaddg(1,b);
- else
- ++b->n[0];
-
- while (!b->n[--size]);
-
- b->sign = size+1;
-}
-
-void
-addg(
- giant a,
- giant b
-)
-/* b := b + a, any signs any result. */
-{
- int asgn = a->sign, bsgn = b->sign;
-
- if (asgn == 0)
- return;
- if (bsgn == 0)
- {
- gtog(a,b);
- return;
- }
- if ((asgn < 0) == (bsgn < 0))
- {
- if (bsgn > 0)
- {
- normal_addg(a,b);
- return;
- }
- absg(b);
- if(a != b) absg(a);
- normal_addg(a,b);
- negg(b);
- if(a != b) negg(a);
- return;
- }
- if(bsgn > 0)
- {
- negg(a);
- if (gcompg(b,a) >= 0)
- {
- normal_subg(a,b);
- negg(a);
- return;
- }
- reverse_subg(a,b);
- negg(a);
- negg(b);
- return;
- }
- negg(b);
- if(gcompg(b,a) < 0)
- {
- reverse_subg(a,b);
- return;
- }
- normal_subg(a,b);
- negg(b);
- return;
-}
-
-void
-subg(
- giant a,
- giant b
-)
-/* b := b - a, any signs, any result. */
-{
- int asgn = a->sign, bsgn = b->sign;
-
- if (asgn == 0)
- return;
- if (bsgn == 0)
- {
- gtog(a,b);
- negg(b);
- return;
- }
- if ((asgn < 0) != (bsgn < 0))
- {
- if (bsgn > 0)
- {
- negg(a);
- normal_addg(a,b);
- negg(a);
- return;
- }
- negg(b);
- normal_addg(a,b);
- negg(b);
- return;
- }
- if (bsgn > 0)
- {
- if (gcompg(b,a) >= 0)
- {
- normal_subg(a,b);
- return;
- }
- reverse_subg(a,b);
- negg(b);
- return;
- }
- negg(a);
- negg(b);
- if (gcompg(b,a) >= 0)
- {
- normal_subg(a,b);
- negg(a);
- negg(b);
- return;
- }
- reverse_subg(a,b);
- negg(a);
- return;
-}
-
-
-int
-numtrailzeros(
- giant g
-)
-/* Returns the number of trailing zero bits in g. */
-{
- register int numshorts = abs(g->sign), j, bcount=0;
- register unsigned short gshort, c;
-
- for (j=0;j<numshorts;j++)
- {
- gshort = g->n[j];
- c = 1;
- for (bcount=0;bcount<16; bcount++)
- {
- if (c & gshort)
- break;
- c <<= 1;
- }
- if (bcount<16)
- break;
- }
- return(bcount + 16*j);
-}
-
-
-void
-bdivg(
- giant v,
- giant u
-)
-/* u becomes greatest power of two not exceeding u/v. */
-{
- int diff = bitlen(u) - bitlen(v);
- giant scratch7;
-
- if (diff<0)
- {
- itog(0,u);
- return;
- }
- scratch7 = popg();
- gtog(v, scratch7);
- gshiftleft(diff,scratch7);
- if (gcompg(u,scratch7) < 0)
- diff--;
- if (diff<0)
- {
- itog(0,u);
- pushg(1);
- return;
- }
- itog(1,u);
- gshiftleft(diff,u);
-
- pushg(1);
-}
-
-
-int
-binvaux(
- giant p,
- giant x
-)
-/* Binary inverse method. Returns zero if no inverse exists,
- * in which case x becomes GCD(x,p). */
-{
-
- giant scratch7, u0, u1, v0, v1;
-
- if (isone(x))
- return(1);
- u0 = popg();
- u1 = popg();
- v0 = popg();
- v1 = popg();
- itog(1, v0);
- gtog(x, v1);
- itog(0,x);
- gtog(p, u1);
-
- scratch7 = popg();
- while(!isZero(v1))
- {
- gtog(u1, u0);
- bdivg(v1, u0);
- gtog(x, scratch7);
- gtog(v0, x);
- mulg(u0, v0);
- subg(v0,scratch7);
- gtog(scratch7, v0);
-
- gtog(u1, scratch7);
- gtog(v1, u1);
- mulg(u0, v1);
- subg(v1,scratch7);
- gtog(scratch7, v1);
- }
-
- pushg(1);
-
- if (!isone(u1))
- {
- gtog(u1,x);
- if(x->sign<0) addg(p, x);
- pushg(4);
- return(0);
- }
- if(x->sign<0)
- addg(p, x);
- pushg(4);
- return(1);
-}
-
-
-int
-binvg(
- giant p,
- giant x
-)
-{
- modg(p, x);
- return(binvaux(p,x));
-}
-
-
-int
-invg(
- giant p,
- giant x
-)
-{
- modg(p, x);
- return(invaux(p,x));
-}
-
-int
-invaux(
- giant p,
- giant x
-)
-/* Returns zero if no inverse exists, in which case x becomes
- * GCD(x,p). */
-{
-
- giant scratch7, u0, u1, v0, v1;
-
- if ((x->sign==1)&&(x->n[0]==1))
- return(1);
-
- u0 = popg();
- u1 = popg();
- v0 = popg();
- v1 = popg();
-
- itog(1,u1);
- gtog(p, v0);
- gtog(x, v1);
- itog(0,x);
-
- scratch7 = popg();
- while (!isZero(v1))
- {
- gtog(v0, u0);
- divg(v1, u0);
- gtog(u0, scratch7);
- mulg(v1, scratch7);
- subg(v0, scratch7);
- negg(scratch7);
- gtog(v1, v0);
- gtog(scratch7, v1);
- gtog(u1, scratch7);
- mulg(u0, scratch7);
- subg(x, scratch7);
- negg(scratch7);
- gtog(u1,x);
- gtog(scratch7, u1);
- }
- pushg(1);
-
- if ((v0->sign!=1)||(v0->n[0]!=1))
- {
- gtog(v0,x);
- pushg(4);
- return(0);
- }
- if(x->sign<0)
- addg(p, x);
- pushg(4);
- return(1);
-}
-
-
-int
-mersenneinvg(
- int q,
- giant x
-)
-{
- int k;
- giant u0, u1, v1;
-
- u0 = popg();
- u1 = popg();
- v1 = popg();
-
- itog(1, u0);
- itog(0, u1);
- itog(1, v1);
- gshiftleft(q, v1);
- subg(u0, v1);
- mersennemod(q, x);
- while (1)
- {
- k = -1;
- if (isZero(x))
- {
- gtog(v1, x);
- pushg(3);
- return(0);
- }
- while (bitval(x, ++k) == 0);
-
- gshiftright(k, x);
- if (k)
- {
- gshiftleft(q-k, u0);
- mersennemod(q, u0);
- }
- if (isone(x))
- break;
- addg(u1, u0);
- mersennemod(q, u0);
- negg(u1);
- addg(u0, u1);
- mersennemod(q, u1);
- if (!gcompg(v1,x)) {
- pushg(3);
- return(0);
- }
- addg(v1, x);
- negg(v1);
- addg(x, v1);
- mersennemod(q, v1);
- }
- gtog(u0, x);
- mersennemod(q,x);
- pushg(3);
- return(1);
-}
-
-
-void
-cgcdg(
- giant a,
- giant v
-)
-/* Classical Euclid GCD. v becomes gcd(a, v). */
-{
- giant u, r;
-
- v->sign = abs(v->sign);
- if (isZero(a))
- return;
-
- u = popg();
- r = popg();
- gtog(a, u);
- u->sign = abs(u->sign);
- while (!isZero(v))
- {
- gtog(u, r);
- modg(v, r);
- gtog(v, u);
- gtog(r, v);
- }
- gtog(u,v);
- pushg(2);
-}
-
-
-void
-gcdg(
- giant x,
- giant y
-)
-{
- if (bitlen(y)<= GCDLIMIT)
- bgcdg(x,y);
- else
- ggcd(x,y);
-}
-
-void
-bgcdg(
- giant a,
- giant b
-)
-/* Binary form of the gcd. b becomes the gcd of a,b. */
-{
- int k = isZero(b), m = isZero(a);
- giant u, v, t;
-
- if (k || m)
- {
- if (m)
- {
- if (k)
- itog(1,b);
- return;
- }
- if (k)
- {
- if (m)
- itog(1,b);
- else
- gtog(a,b);
- return;
- }
- }
-
- u = popg();
- v = popg();
- t = popg();
-
- /* Now neither a nor b is zero. */
- gtog(a, u);
- u->sign = abs(a->sign);
- gtog(b, v);
- v->sign = abs(b->sign);
- k = numtrailzeros(u);
- m = numtrailzeros(v);
- if (k>m)
- k = m;
- gshiftright(k,u);
- gshiftright(k,v);
- if (u->n[0] & 1)
- {
- gtog(v, t);
- negg(t);
- }
- else
- {
- gtog(u,t);
- }
-
- while (!isZero(t))
- {
- m = numtrailzeros(t);
- gshiftright(m, t);
- if (t->sign > 0)
- {
- gtog(t, u);
- subg(v,t);
- }
- else
- {
- gtog(t, v);
- negg(v);
- addg(u,t);
- }
- }
- gtog(u,b);
- gshiftleft(k, b);
- pushg(3);
-}
-
-
-void
-powerg(
- int m,
- int n,
- giant g
-)
-/* g becomes m^n, NO mod performed. */
-{
- giant scratch2 = popg();
-
- itog(1, g);
- itog(m, scratch2);
- while (n)
- {
- if (n & 1)
- mulg(scratch2, g);
- n >>= 1;
- if (n)
- squareg(scratch2);
- }
- pushg(1);
-}
-
-#if 0
-void
-jtest(
- giant n
-)
-{
- if (n->sign)
- {
- if (n->n[n->sign-1] == 0)
- {
- fprintf(stderr,"%d %d tilt",n->sign, (int)(n->n[n->sign-1]));
- exit(7);
- }
- }
-}
-#endif
-
-
-void
-make_recip(
- giant d,
- giant r
-)
-/* r becomes the steady-state reciprocal
- * 2^(2b)/d, where b = bit-length of d-1. */
-{
- int b;
- giant tmp, tmp2;
-
- if (isZero(d) || (d->sign < 0))
- {
- exit(SIGN);
- }
- tmp = popg();
- tmp2 = popg();
- itog(1, r);
- subg(r, d);
- b = bitlen(d);
- addg(r, d);
- gshiftleft(b, r);
- gtog(r, tmp2);
- while (1)
- {
- gtog(r, tmp);
- squareg(tmp);
- gshiftright(b, tmp);
- mulg(d, tmp);
- gshiftright(b, tmp);
- addg(r, r);
- subg(tmp, r);
- if (gcompg(r, tmp2) <= 0)
- break;
- gtog(r, tmp2);
- }
- itog(1, tmp);
- gshiftleft(2*b, tmp);
- gtog(r, tmp2);
- mulg(d, tmp2);
- subg(tmp2, tmp);
- itog(1, tmp2);
- while (tmp->sign < 0)
- {
- subg(tmp2, r);
- addg(d, tmp);
- }
- pushg(2);
-}
-
-void
-divg_via_recip(
- giant d,
- giant r,
- giant n
-)
-/* n := n/d, where r is the precalculated
- * steady-state reciprocal of d. */
-{
- int s = 2*(bitlen(r)-1), sign = gsign(n);
- giant tmp, tmp2;
-
- if (isZero(d) || (d->sign < 0))
- {
- exit(SIGN);
- }
-
- tmp = popg();
- tmp2 = popg();
-
- n->sign = abs(n->sign);
- itog(0, tmp2);
- while (1)
- {
- gtog(n, tmp);
- mulg(r, tmp);
- gshiftright(s, tmp);
- addg(tmp, tmp2);
- mulg(d, tmp);
- subg(tmp, n);
- if (gcompg(n,d) >= 0)
- {
- subg(d,n);
- iaddg(1, tmp2);
- }
- if (gcompg(n,d) < 0)
- break;
- }
- gtog(tmp2, n);
- n->sign *= sign;
- pushg(2);
-}
-
-#if 1
-void
-modg_via_recip(
- giant d,
- giant r,
- giant n
-)
-/* This is the fastest mod of the present collection.
- * n := n % d, where r is the precalculated
- * steady-state reciprocal of d. */
-
-{
- int s = (bitlen(r)-1), sign = n->sign;
- giant tmp, tmp2;
-
- if (isZero(d) || (d->sign < 0))
- {
- exit(SIGN);
- }
-
- tmp = popg();
- tmp2 = popg();
-
- n->sign = abs(n->sign);
- while (1)
- {
- gtog(n, tmp); gshiftright(s-1, tmp);
- mulg(r, tmp);
- gshiftright(s+1, tmp);
- mulg(d, tmp);
- subg(tmp, n);
- if (gcompg(n,d) >= 0)
- subg(d,n);
- if (gcompg(n,d) < 0)
- break;
- }
- if (sign >= 0)
- goto done;
- if (isZero(n))
- goto done;
- negg(n);
- addg(d,n);
-done:
- pushg(2);
- return;
-}
-
-#else
-void
-modg_via_recip(
- giant d,
- giant r,
- giant n
-)
-{
- int s = 2*(bitlen(r)-1), sign = n->sign;
- giant tmp, tmp2;
-
- if (isZero(d) || (d->sign < 0))
- {
- exit(SIGN);
- }
-
- tmp = popg();
- tmp2 = popg()
-
- n->sign = abs(n->sign);
- while (1)
- {
- gtog(n, tmp);
- mulg(r, tmp);
- gshiftright(s, tmp);
- mulg(d, tmp);
- subg(tmp, n);
- if (gcompg(n,d) >= 0)
- subg(d,n);
- if (gcompg(n,d) < 0)
- break;
- }
- if (sign >= 0)
- goto done;
- if (isZero(n))
- goto done;
- negg(n);
- addg(d,n);
-done:
- pushg(2);
- return;
-}
-#endif
-
-void
-modg(
- giant d,
- giant n
-)
-/* n becomes n%d. n is arbitrary, but the denominator d must be positive! */
-{
- if (cur_recip == NULL) {
- cur_recip = newgiant(current_max_size);
- cur_den = newgiant(current_max_size);
- gtog(d, cur_den);
- make_recip(d, cur_recip);
- } else if (gcompg(d, cur_den)) {
- gtog(d, cur_den);
- make_recip(d, cur_recip);
- }
- modg_via_recip(d, cur_recip, n);
-}
-
-
-#if 0
-int
-feemulmod (
- giant a,
- giant b,
- int q,
- int k
-)
-/* a becomes (a*b) (mod 2^q-k) where q % 16 == 0 and k is "small" (0 < k < 65535).
- * Returns 0 if unsuccessful, otherwise 1. */
-{
- giant carry, kk, scratch;
- int i, j;
- int asize = abs(a->sign), bsize = abs(b->sign);
- unsigned short *aptr,*bptr,*destptr;
- unsigned int words;
- int kpower, curk;
-
- if ((q % 16) || (k <= 0) || (k >= 65535)) {
- return (0);
- }
-
- carry = popg();
- kk = popg();
- scratch = popg();
-
- for (i=0; i<asize+bsize; i++) scratch->n[i]=0;
-
- words = q >> 4;
-
- bptr = b->n;
- for (i = 0; i < bsize; i++) {
- mult = *bptr++;
- if (mult) {
- kpower = i/words;
-
- if (kpower >= 1) itog (kpower,kk);
- for (j = 1; j < kpower; k++) smulg(kpower,kk);
-
- itog(0,carry);
-
- aptr = a->n;
- for (j = 0; j < bsize; b++) {
- gtog(kk,scratch);
- smulg(*aptr++,scratch);
- smulg(mult,scratch);
- iaddg(*destptr,scratch);
- addg(carry,scratch);
- *destptr++ = scratch->n[0];
- gshiftright(scratch,16);
- gtog(scratch,carry);
- if (destptr - scratch->n >= words) {
- smulg(k, carry);
- smulg(k, kk);
- destptr -= words;
- }
- }
- }
- }
-
- int i,j,m;
- unsigned int prod,carry=0;
- int asize = abs(a->sign), bsize = abs(b->sign);
- unsigned short *aptr,*bptr,*destptr;
- unsigned short mult;
- int words, excess;
- int temp;
- giant scratch = popg(), scratch2 = popg(), scratch3 = popg();
- short *carryptr = scratch->n;
- int kpower,kpowerlimit, curk;
-
- if ((q % 16) || (k <= 0) || (k >= 65535)) {
- return (0);
- }
-
- scratch
-
- for (i=0; i<asize+bsize; i++) scratch->n[i]=0;
-
- words = q >> 4;
-
- bptr = b->n;
- for (i=0; i<bsize; ++i)
- {
- mult = *bptr++;
- if (mult)
- {
- kpower = i/words;
- aptr = a->n;
- destptr = scratch->n + i;
-
- if (kpower == 0) {
- carry = 0;
- } else if (kpower <= kpowerlimit) {
- carry = 0;
- curk = k;
- for (j = 1; j < kpower; j++) curk *= k;
- } else {
- itog (k,scratch);
- for (j = 1; j < kpower; j++) smulg(k,scratch);
- itog(0,scratch2);
- }
-
- for (j = 0; j < asize; j++) {
- if(kpower == 0) {
- prod = *aptr++ * mult + *destptr + carry;
- *destptr++ = (unsigned short)(prod & 0xFFFF);
- carry = prod >> 16;
- } else if (kpower < kpowerlimit) {
- prod = kcur * *aptr++;
- temp = prod >> 16;
- prod &= 0xFFFF;
- temp *= mult;
- prod *= mult;
- temp += prod >> 16;
- prod &= 0xFFFF;
- prod += *destptr + carry;
- carry = prod >> 16 + temp;
- *destptr++ = (unsigned short)(prod & 0xFFFF);
- } else {
- gtog(scratch,scratch3);
- smulg(*aptr++,scratch3);
- smulg(mult,scratch3);
- iaddg(*destptr,scratch3);
- addg(scratch3,scratch2);
- *destptr++ = scratch2->n[0];
- memmove(scratch2->n,scratch2->n+1,2*(scratch2->size-1));
- scratch2->sign--;
- }
- if (destptr - scratch->n > words) {
- if (kpower == 0) {
- curk = k;
- carry *= k;
- } else if (kpower < kpowerlimit) {
- curk *= k;
- carry *= curk;
- } else if (kpower == kpowerlimit) {
- itog (k,scratch);
- for (j = 1; j < kpower; j++) smulg(k,scratch);
- itog(carry,scratch2);
- smulg(k,scratch2);
- } else {
- smulg(k,scratch);
- smulg(k,scratch2);
- }
- kpower++;
- destptr -= words;
- }
- }
-
- /* Next, deal with the carry term. Needs to be improved to
- handle overflow carry cases. */
- if (kpower <= kpowerlimit) {
- iaddg(carry,scratch);
- } else {
- addg(scratch2,scratch);
- }
- while(scratch->sign > q)
- gtog(scratch,scratch2)
- }
- }
- scratch->sign = destptr - scratch->n;
- if (!carry)
- --(scratch->sign);
- scratch->sign *= gsign(a)*gsign(b);
- gtog(scratch,a);
- pushg(3);
- return (1);
-}
-#endif
-
-int
-idivg(
- int divisor,
- giant theg
-)
-{
- /* theg becomes theg/divisor. Returns remainder. */
- int n;
- int base = 1<<(8*sizeof(short));
-
- n = radixdiv(base,divisor,theg);
- return(n);
-}
-
-
-void
-divg(
- giant d,
- giant n
-)
-/* n becomes n/d. n is arbitrary, but the denominator d must be positive! */
-{
- if (cur_recip == NULL) {
- cur_recip = newgiant(current_max_size);
- cur_den = newgiant(current_max_size);
- gtog(d, cur_den);
- make_recip(d, cur_recip);
- } else if (gcompg(d, cur_den)) {
- gtog(d, cur_den);
- make_recip(d, cur_recip);
- }
- divg_via_recip(d, cur_recip, n);
-}
-
-
-void
-powermod(
- giant x,
- int n,
- giant g
-)
-/* x becomes x^n (mod g). */
-{
- giant scratch2 = popg();
- gtog(x, scratch2);
- itog(1, x);
- while (n)
- {
- if (n & 1)
- {
- mulg(scratch2, x);
- modg(g, x);
- }
- n >>= 1;
- if (n)
- {
- squareg(scratch2);
- modg(g, scratch2);
- }
- }
- pushg(1);
-}
-
-
-void
-powermodg(
- giant x,
- giant n,
- giant g
-)
-/* x becomes x^n (mod g). */
-{
- int len, pos;
- giant scratch2 = popg();
-
- gtog(x, scratch2);
- itog(1, x);
- len = bitlen(n);
- pos = 0;
- while (1)
- {
- if (bitval(n, pos++))
- {
- mulg(scratch2, x);
- modg(g, x);
- }
- if (pos>=len)
- break;
- squareg(scratch2);
- modg(g, scratch2);
- }
- pushg(1);
-}
-
-
-void
-fermatpowermod(
- giant x,
- int n,
- int q
-)
-/* x becomes x^n (mod 2^q+1). */
-{
- giant scratch2 = popg();
-
- gtog(x, scratch2);
- itog(1, x);
- while (n)
- {
- if (n & 1)
- {
- mulg(scratch2, x);
- fermatmod(q, x);
- }
- n >>= 1;
- if (n)
- {
- squareg(scratch2);
- fermatmod(q, scratch2);
- }
- }
- pushg(1);
-}
-
-
-void
-fermatpowermodg(
- giant x,
- giant n,
- int q
-)
-/* x becomes x^n (mod 2^q+1). */
-{
- int len, pos;
- giant scratch2 = popg();
-
- gtog(x, scratch2);
- itog(1, x);
- len = bitlen(n);
- pos = 0;
- while (1)
- {
- if (bitval(n, pos++))
- {
- mulg(scratch2, x);
- fermatmod(q, x);
- }
- if (pos>=len)
- break;
- squareg(scratch2);
- fermatmod(q, scratch2);
- }
- pushg(1);
-}
-
-
-void
-mersennepowermod(
- giant x,
- int n,
- int q
-)
-/* x becomes x^n (mod 2^q-1). */
-{
- giant scratch2 = popg();
-
- gtog(x, scratch2);
- itog(1, x);
- while (n)
- {
- if (n & 1)
- {
- mulg(scratch2, x);
- mersennemod(q, x);
- }
- n >>= 1;
- if (n)
- {
- squareg(scratch2);
- mersennemod(q, scratch2);
- }
- }
- pushg(1);
-}
-
-
-void
-mersennepowermodg(
- giant x,
- giant n,
- int q
-)
-/* x becomes x^n (mod 2^q-1). */
-{
- int len, pos;
- giant scratch2 = popg();
-
- gtog(x, scratch2);
- itog(1, x);
- len = bitlen(n);
- pos = 0;
- while (1)
- {
- if (bitval(n, pos++))
- {
- mulg(scratch2, x);
- mersennemod(q, x);
- }
- if (pos>=len)
- break;
- squareg(scratch2);
- mersennemod(q, scratch2);
- }
- pushg(1);
-}
-
-
-void
-gshiftleft(
- int bits,
- giant g
-)
-/* shift g left bits bits. Equivalent to g = g*2^bits. */
-{
- int rem = bits&15, crem = 16-rem, words = bits>>4;
- int size = abs(g->sign), j, k, sign = gsign(g);
- unsigned short carry, dat;
-
- if (!bits)
- return;
- if (!size)
- return;
- if (bits < 0) {
- gshiftright(-bits,g);
- return;
- }
- if (size+words+1 > current_max_size) {
- error = OVFLOW;
- exit(error);
- }
- if (rem == 0) {
- memmove(g->n + words, g->n, size * sizeof(short));
- for (j = 0; j < words; j++) g->n[j] = 0;
- g->sign += (g->sign < 0)?(-words):(words);
- } else {
- k = size+words;
- carry = 0;
- for (j=size-1; j>=0; j--) {
- dat = g->n[j];
- g->n[k--] = (unsigned short)((dat >> crem) | carry);
- carry = (unsigned short)(dat << rem);
- }
- do {
- g->n[k--] = carry;
- carry = 0;
- } while(k>=0);
-
- k = size+words;
- if (g->n[k] == 0)
- --k;
- g->sign = sign*(k+1);
- }
-}
-
-
-void
-gshiftright(
- int bits,
- giant g
-)
-/* shift g right bits bits. Equivalent to g = g/2^bits. */
-{
- register int j,size=abs(g->sign);
- register unsigned int carry;
- int words = bits >> 4;
- int remain = bits & 15, cremain = (16-remain);
-
- if (bits==0)
- return;
- if (isZero(g))
- return;
- if (bits < 0) {
- gshiftleft(-bits,g);
- return;
- }
- if (words >= size) {
- g->sign = 0;
- return;
- }
- if (remain == 0) {
- memmove(g->n,g->n + words,(size - words) * sizeof(short));
- g->sign += (g->sign < 0)?(words):(-words);
- } else {
- size -= words;
-
- if (size)
- {
- for(j=0;j<size-1;++j)
- {
- carry = g->n[j+words+1] << cremain;
- g->n[j] = (unsigned short)((g->n[j+words] >> remain ) | carry);
- }
- g->n[size-1] = (unsigned short)(g->n[size-1+words] >> remain);
- }
-
- if (g->n[size-1] == 0)
- --size;
-
- if (g->sign > 0)
- g->sign = size;
- else
- g->sign = -size;
- }
-}
-
-
-void
-extractbits(
- int n,
- giant src,
- giant dest
-)
-/* dest becomes lowermost n bits of src. Equivalent to dest = src % 2^n. */
-{
- register int words = n >> 4, numbytes = words*sizeof(short);
- register int bits = n & 15;
-
- if (n<=0)
- return;
- if (words >= abs(src->sign))
- gtog(src,dest);
- else
- {
- memcpy((char *)(dest->n), (char *)(src->n), numbytes);
- if (bits)
- {
- dest->n[words] = (unsigned short)(src->n[words] & ((1<<bits)-1));
- ++words;
- }
- while ((dest->n[words-1] == 0) && (words > 0))
- {
- --words;
- }
- if (src->sign<0)
- dest->sign = -words;
- else
- dest->sign = words;
- }
-}
-
-
-int
-allzeros(
- int shorts,
- int bits,
- giant g
-)
-{
- int i=shorts;
-
- while (i>0)
- {
- if (g->n[--i])
- return(0);
- }
- return((int)(!(g->n[shorts] & ((1<<bits)-1))));
-}
-
-
-void
-fermatnegate(
- int n,
- giant g
-)
-/* negate g. g is mod 2^n+1. */
-{
- register int shorts = n>>4,
- bits = n & 15,
- i = shorts,
- mask = 1<<bits;
- register unsigned carry,temp;
-
- for (temp=(unsigned)shorts; (int)temp>g->sign-1; --temp)
- {
- g->n[temp] = 0;
- }
- if (g->n[shorts] & mask)
- { /* if high bit is set, -g = 1. */
- g->sign = 1;
- g->n[0] = 1;
- return;
- }
- if (allzeros(shorts,bits,g))
- return; /* if g=0, -g = 0. */
-
- while (i>0)
- { --i;
- g->n[i] = (unsigned short)(~(g->n[i+1]));
- }
- g->n[shorts] ^= mask-1;
-
- carry = 2;
- i = 0;
- while (carry)
- {
- temp = g->n[i]+carry;
- g->n[i++] = (unsigned short)(temp & 0xffff);
- carry = temp>>16;
- }
- while(!g->n[shorts])
- {
- --shorts;
- }
- g->sign = shorts+1;
-}
-
-
-void
-mersennemod (
- int n,
- giant g
-)
-/* g := g (mod 2^n - 1) */
-{
- int the_sign, s;
- giant scratch3 = popg(), scratch4 = popg();
-
- if ((the_sign = gsign(g)) < 0) absg(g);
- while (bitlen(g) > n) {
- gtog(g,scratch3);
- gshiftright(n,scratch3);
- addg(scratch3,g);
- gshiftleft(n,scratch3);
- subg(scratch3,g);
- }
- if(!isZero(g)) {
- if ((s = gsign(g)) < 0) absg(g);
- itog(1,scratch3);
- gshiftleft(n,scratch3);
- itog(1,scratch4);
- subg(scratch4,scratch3);
- if(gcompg(g,scratch3) >= 0) subg(scratch3,g);
- if (s < 0) {
- g->sign = -g->sign;
- addg(scratch3,g);
- }
- if (the_sign < 0) {
- g->sign = -g->sign;
- addg(scratch3,g);
- }
- }
- pushg(2);
-}
-
-void
-fermatmod (
- int n,
- giant g
-)
-/* g := g (mod 2^n + 1), */
-{
- int the_sign, s;
- giant scratch3 = popg();
-
- if ((the_sign = gsign(g)) < 0) absg(g);
- while (bitlen(g) > n) {
- gtog(g,scratch3);
- gshiftright(n,scratch3);
- subg(scratch3,g);
- gshiftleft(n,scratch3);
- subg(scratch3,g);
- }
- if((bitlen(g) < n) && (the_sign * (g->sign) >= 0)) goto leave;
- if(!isZero(g)) {
- if ((s = gsign(g)) < 0) absg(g);
- itog(1,scratch3);
- gshiftleft(n,scratch3);
- iaddg(1,scratch3);
- if(gcompg(g,scratch3) >= 0) subg(scratch3,g);
- if (s * the_sign < 0) {
- g->sign = -g->sign;
- addg(scratch3,g);
- }
- }
-leave:
- pushg(1);
-
-}
-
-void
-fer_mod (
- int n,
- giant g,
- giant modulus
-)
-/* Same as fermatmod(), except modulus = 2^n should be passed
-if available (i.e. if already allocated and set). */
-{
- int the_sign, s;
- giant scratch3 = popg();
-
- if ((the_sign = gsign(g)) < 0) absg(g);
- while (bitlen(g) > n) {
- gtog(g,scratch3);
- gshiftright(n,scratch3);
- subg(scratch3,g);
- gshiftleft(n,scratch3);
- subg(scratch3,g);
- }
- if((bitlen(g) < n) && (the_sign * (g->sign) >= 0)) goto leave;
- if(!isZero(g)) {
- if ((s = gsign(g)) < 0) absg(g);
- if(gcompg(g,modulus) >= 0) subg(modulus,g);
- if (s * the_sign < 0) {
- g->sign = -g->sign;
- addg(modulus,g);
- }
- }
-leave:
- pushg(1);
-}
-
-
-void
-smulg(
- unsigned short i,
- giant g
-)
-/* g becomes g * i. */
-{
- unsigned short carry = 0;
- int size = abs(g->sign);
- register int j,k,mul = abs(i);
- unsigned short *digit = g->n;
-
- for (j=0; j<size; ++j)
- {
- k = *digit * mul + carry;
- carry = (unsigned short)(k>>16);
- *digit = (unsigned short)(k & 0xffff);
- ++digit;
- }
- if (carry)
- {
- if (++j >= current_max_size)
- {
- error = OVFLOW;
- exit(error);
- }
- *digit = carry;
- }
-
- if ((g->sign>0) ^ (i>0))
- g->sign = -j;
- else
- g->sign = j;
-}
-
-
-void
-squareg(
- giant b
-)
-/* b becomes b^2. */
-{
- auxmulg(b,b);
-}
-
-
-void
-mulg(
- giant a,
- giant b
-)
-/* b becomes a*b. */
-{
- auxmulg(a,b);
-}
-
-
-void
-auxmulg(
- giant a,
- giant b
-)
-/* Optimized general multiply, b becomes a*b. Modes are:
- * AUTO_MUL: switch according to empirical speed criteria.
- * GRAMMAR_MUL: force grammar-school algorithm.
- * KARAT_MUL: force Karatsuba divide-conquer method.
- * FFT_MUL: force floating point FFT method. */
-{
- float grammartime;
- int square = (a==b);
- int sizea, sizeb;
-
- switch (mulmode)
- {
- case GRAMMAR_MUL:
- if (square) grammarsquareg(b);
- else grammarmulg(a,b);
- break;
- case FFT_MUL:
- if (square)
- FFTsquareg(b);
- else
- FFTmulg(a,b);
- break;
- case KARAT_MUL:
- if (square) karatsquareg(b);
- else karatmulg(a,b);
- break;
- case AUTO_MUL:
- sizea = abs(a->sign);
- sizeb = abs(b->sign);
- if((sizea > KARAT_BREAK) && (sizea <= FFT_BREAK) &&
- (sizeb > KARAT_BREAK) && (sizeb <= FFT_BREAK)){
- if(square) karatsquareg(b);
- else karatmulg(a,b);
-
- } else {
- grammartime = (float)sizea;
- grammartime *= (float)sizeb;
- if (grammartime < FFT_BREAK * FFT_BREAK)
- {
- if (square) grammarsquareg(b);
- else grammarmulg(a,b);
- }
- else
- {
- if (square) FFTsquareg(b);
- else FFTmulg(a,b);
- }
- }
- break;
- }
-}
-
-void
-justg(giant x) {
- int s = x->sign, sg = 1;
-
- if(s<0) {
- sg = -1;
- s = -s;
- }
- --s;
- while(x->n[s] == 0) {
- --s;
- if(s < 0) break;
- }
- x->sign = sg*(s+1);
-}
-
-/* Next, improved Karatsuba routines from A. Powell,
- improvements by G. Woltman. */
-
-void
-karatmulg(giant x, giant y)
-/* y becomes x*y. */
-{
- int s = abs(x->sign), t = abs(y->sign), w, bits,
- sg = gsign(x)*gsign(y);
- giant a, b, c, d, e, f;
-
- if((s <= KARAT_BREAK) || (t <= KARAT_BREAK)) {
- grammarmulg(x,y);
- return;
- }
- w = (s + t + 2)/4; bits = 16*w;
- a = popg(); b = popg(); c = popg();
- d = popg(); e = popg(); f = popg();
- gtog(x,a); absg(a); if (w <= s) {a->sign = w; justg(a);}
- gtog(x,b); absg(b);
- gshiftright(bits, b);
- gtog(y,c); absg(c); if (w <= t) {c->sign = w; justg(c);}
- gtog(y,d); absg(d);
- gshiftright(bits,d);
- gtog(a,e); normal_addg(b,e); /* e := (a + b) */
- gtog(c,f); normal_addg(d,f); /* f := (c + d) */
- karatmulg(e,f); /* f := (a + b)(c + d) */
- karatmulg(c,a); /* a := a c */
- karatmulg(d,b); /* b := b d */
- normal_subg(a,f);
- /* f := (a + b)(c + d) - a c */
- normal_subg(b,f);
- /* f := (a + b)(c + d) - a c - b d */
- gshiftleft(bits, b);
- normal_addg(f, b);
- gshiftleft(bits, b);
- normal_addg(a, b);
- gtog(b, y); y->sign *= sg;
- pushg(6);
-
- return;
-}
-
-void
-karatsquareg(giant x)
-/* x becomes x^2. */
-{
- int s = abs(x->sign), w, bits;
- giant a, b, c;
-
- if(s <= KARAT_BREAK) {
- grammarsquareg(x);
- return;
- }
- w = (s+1)/2; bits = 16*w;
- a = popg(); b = popg(); c = popg();
- gtog(x, a); a->sign = w; justg(a);
- gtog(x, b); absg(b);
- gshiftright(bits, b);
- gtog(a,c); normal_addg(b,c);
- karatsquareg(c);
- karatsquareg(a);
- karatsquareg(b);
- normal_subg(b, c);
- normal_subg(a, c);
- gshiftleft(bits, b);
- normal_addg(c,b);
- gshiftleft(bits, b);
- normal_addg(a, b);
- gtog(b, x);
- pushg(3);
-
- return;
-}
-
-void
-grammarmulg(
- giant a,
- giant b
-)
-/* b becomes a*b. */
-{
- int i,j;
- unsigned int prod,carry=0;
- int asize = abs(a->sign), bsize = abs(b->sign);
- unsigned short *aptr,*bptr,*destptr;
- unsigned short mult;
- giant scratch = popg();
-
- for (i=0; i<asize+bsize; ++i)
- {
- scratch->n[i]=0;
- }
-
- bptr = &(b->n[0]);
- for (i=0; i<bsize; ++i)
- {
- mult = *(bptr++);
- if (mult)
- {
- carry = 0;
- aptr = &(a->n[0]);
- destptr = &(scratch->n[i]);
- for (j=0; j<asize; ++j)
- {
- prod = *(aptr++) * mult + *destptr + carry;
- *(destptr++) = (unsigned short)(prod & 0xffff);
- carry = prod >> 16;
- }
- *destptr = (unsigned short)carry;
- }
- }
- bsize+=asize;
- if (!carry)
- --bsize;
- scratch->sign = gsign(a)*gsign(b)*bsize;
- gtog(scratch,b);
- pushg(1);
-}
-
-
-void
-grammarsquareg (
- giant a
-)
-/* a := a^2. */
-{
- unsigned int cur_term;
- unsigned int prod, carry=0, temp;
- int asize = abs(a->sign), max = asize * 2 - 1;
- unsigned short *ptr = a->n, *ptr1, *ptr2;
- giant scratch;
-
- if(asize == 0) {
- itog(0,a);
- return;
- }
-
- scratch = popg();
-
- asize--;
-
- temp = *ptr;
- temp *= temp;
- scratch->n[0] = temp;
- carry = temp >> 16;
-
- for (cur_term = 1; cur_term < max; cur_term++) {
- ptr1 = ptr2 = ptr;
- if (cur_term <= asize) {
- ptr2 += cur_term;
- } else {
- ptr1 += cur_term - asize;
- ptr2 += asize;
- }
- prod = carry & 0xFFFF;
- carry >>= 16;
- while(ptr1 < ptr2) {
- temp = *ptr1++ * *ptr2--;
- prod += (temp << 1) & 0xFFFF;
- carry += (temp >> 15);
- }
- if (ptr1 == ptr2) {
- temp = *ptr1;
- temp *= temp;
- prod += temp & 0xFFFF;
- carry += (temp >> 16);
- }
- carry += prod >> 16;
- scratch->n[cur_term] = (unsigned short) (prod);
- }
- if (carry) {
- scratch->n[cur_term] = carry;
- scratch->sign = cur_term+1;
- } else scratch->sign = cur_term;
-
- gtog(scratch,a);
- pushg(1);
-}
-
-
-/**************************************************************
- *
- * FFT multiply Functions
- *
- **************************************************************/
-
-int initL = 0;
-
-int
-lpt(
- int n,
- int *lambda
-)
-/* Returns least power of two greater than n. */
-{
- register int i = 1;
-
- *lambda = 0;
- while (i<n)
- {
- i<<=1;
- ++(*lambda);
- }
- return(i);
-}
-
-
-void
-addsignal(
- giant x,
- double *z,
- int n
-)
-{
- register int j, k, m, car, last;
- register double f, g,err;
-
- maxFFTerror = 0;
- last = 0;
- for (j=0;j<n;j++)
- {
- f = gfloor(z[j]+0.5);
- if(f != 0.0) last = j;
- if (checkFFTerror)
- {
- err = fabs(f - z[j]);
- if (err > maxFFTerror)
- maxFFTerror = err;
- }
- z[j] =0;
- k = 0;
- do
- {
- g = gfloor(f*TWOM16);
- z[j+k] += f-g*TWO16;
- ++k;
- f=g;
- } while(f != 0.0);
- }
- car = 0;
- for(j=0;j < last + 1;j++)
- {
- m = (int)(z[j]+car);
- x->n[j] = (unsigned short)(m & 0xffff);
- car = (m>>16);
- }
- if (car)
- x->n[j] = (unsigned short)car;
- else
- --j;
-
- while(!(x->n[j])) --j;
-
- x->sign = j+1;
-}
-
-
-void
-FFTsquareg(
- giant x
-)
-{
- int j,size = abs(x->sign);
- register int L;
-
- if (size<4)
- {
- grammarmulg(x,x);
- return;
- }
- L = lpt(size+size, &j);
- if(!z) z = (double *)malloc(MAX_SHORTS * sizeof(double));
- giant_to_double(x, size, z, L);
- fft_real_to_hermitian(z, L);
- square_hermitian(z, L);
- fftinv_hermitian_to_real(z, L);
- addsignal(x,z,L);
- x->sign = abs(x->sign);
-}
-
-
-void
-FFTmulg(
- giant y,
- giant x
-)
-{
- /* x becomes y*x. */
- int lambda, sizex = abs(x->sign), sizey = abs(y->sign);
- int finalsign = gsign(x)*gsign(y);
- register int L;
-
- if ((sizex<=4)||(sizey<=4))
- {
- grammarmulg(y,x);
- return;
- }
- L = lpt(sizex+sizey, &lambda);
- if(!z) z = (double *)malloc(MAX_SHORTS * sizeof(double));
- if(!z2) z2 = (double *)malloc(MAX_SHORTS * sizeof(double));
-
- giant_to_double(x, sizex, z, L);
- giant_to_double(y, sizey, z2, L);
- fft_real_to_hermitian(z, L);
- fft_real_to_hermitian(z2, L);
- mul_hermitian(z2, z, L);
- fftinv_hermitian_to_real(z, L);
- addsignal(x,z,L);
- x->sign = finalsign*abs(x->sign);
-}
-
-
-void
-scramble_real(
- double *x,
- int n
-)
-{
- register int i,j,k;
- register double tmp;
-
- for (i=0,j=0;i<n-1;i++)
- {
- if (i<j)
- {
- tmp = x[j];
- x[j]=x[i];
- x[i]=tmp;
- }
- k = n/2;
- while (k<=j)
- {
- j -= k;
- k>>=1;
- }
- j += k;
- }
-}
-
-
-void
-fft_real_to_hermitian(
- double *z,
- int n
-)
-/* Output is {Re(z^[0]),...,Re(z^[n/2),Im(z^[n/2-1]),...,Im(z^[1]).
- * This is a decimation-in-time, split-radix algorithm.
- */
-{
- register double cc1, ss1, cc3, ss3;
- register int is, id, i0, i1, i2, i3, i4, i5, i6, i7, i8,
- a, a3, b, b3, nminus = n-1, dil, expand;
- register double *x, e;
- int nn = n>>1;
- double t1, t2, t3, t4, t5, t6;
- register int n2, n4, n8, i, j;
-
- init_sinCos(n);
- expand = cur_run/n;
- scramble_real(z, n);
- x = z-1; /* FORTRAN compatibility. */
- is = 1;
- id = 4;
- do
- {
- for (i0=is;i0<=n;i0+=id)
- {
- i1 = i0+1;
- e = x[i0];
- x[i0] = e + x[i1];
- x[i1] = e - x[i1];
- }
- is = (id<<1)-1;
- id <<= 2;
- } while(is<n);
-
- n2 = 2;
- while(nn>>=1)
- {
- n2 <<= 1;
- n4 = n2>>2;
- n8 = n2>>3;
- is = 0;
- id = n2<<1;
- do
- {
- for (i=is;i<n;i+=id)
- {
- i1 = i+1;
- i2 = i1 + n4;
- i3 = i2 + n4;
- i4 = i3 + n4;
- t1 = x[i4]+x[i3];
- x[i4] -= x[i3];
- x[i3] = x[i1] - t1;
- x[i1] += t1;
- if (n4==1)
- continue;
- i1 += n8;
- i2 += n8;
- i3 += n8;
- i4 += n8;
- t1 = (x[i3]+x[i4])*SQRTHALF;
- t2 = (x[i3]-x[i4])*SQRTHALF;
- x[i4] = x[i2] - t1;
- x[i3] = -x[i2] - t1;
- x[i2] = x[i1] - t2;
- x[i1] += t2;
- }
- is = (id<<1) - n2;
- id <<= 2;
- } while(is<n);
- dil = n/n2;
- a = dil;
- for (j=2;j<=n8;j++)
- {
- a3 = (a+(a<<1))&nminus;
- b = a*expand;
- b3 = a3*expand;
- cc1 = s_cos(b);
- ss1 = s_sin(b);
- cc3 = s_cos(b3);
- ss3 = s_sin(b3);
- a = (a+dil)&nminus;
- is = 0;
- id = n2<<1;
- do
- {
- for(i=is;i<n;i+=id)
- {
- i1 = i+j;
- i2 = i1 + n4;
- i3 = i2 + n4;
- i4 = i3 + n4;
- i5 = i + n4 - j + 2;
- i6 = i5 + n4;
- i7 = i6 + n4;
- i8 = i7 + n4;
- t1 = x[i3]*cc1 + x[i7]*ss1;
- t2 = x[i7]*cc1 - x[i3]*ss1;
- t3 = x[i4]*cc3 + x[i8]*ss3;
- t4 = x[i8]*cc3 - x[i4]*ss3;
- t5 = t1 + t3;
- t6 = t2 + t4;
- t3 = t1 - t3;
- t4 = t2 - t4;
- t2 = x[i6] + t6;
- x[i3] = t6 - x[i6];
- x[i8] = t2;
- t2 = x[i2] - t3;
- x[i7] = -x[i2] - t3;
- x[i4] = t2;
- t1 = x[i1] + t5;
- x[i6] = x[i1] - t5;
- x[i1] = t1;
- t1 = x[i5] + t4;
- x[i5] -= t4;
- x[i2] = t1;
- }
- is = (id<<1) - n2;
- id <<= 2;
- } while(is<n);
- }
- }
-}
-
-
-void
-fftinv_hermitian_to_real(
- double *z,
- int n
-)
-/* Input is {Re(z^[0]),...,Re(z^[n/2),Im(z^[n/2-1]),...,Im(z^[1]).
- * This is a decimation-in-frequency, split-radix algorithm.
- */
-{
- register double cc1, ss1, cc3, ss3;
- register int is, id, i0, i1, i2, i3, i4, i5, i6, i7, i8,
- a, a3, b, b3, nminus = n-1, dil, expand;
- register double *x, e;
- int nn = n>>1;
- double t1, t2, t3, t4, t5;
- int n2, n4, n8, i, j;
-
- init_sinCos(n);
- expand = cur_run/n;
- x = z-1;
- n2 = n<<1;
- while(nn >>= 1)
- {
- is = 0;
- id = n2;
- n2 >>= 1;
- n4 = n2>>2;
- n8 = n4>>1;
- do
- {
- for(i=is;i<n;i+=id)
- {
- i1 = i+1;
- i2 = i1 + n4;
- i3 = i2 + n4;
- i4 = i3 + n4;
- t1 = x[i1] - x[i3];
- x[i1] += x[i3];
- x[i2] += x[i2];
- x[i3] = t1 - 2.0*x[i4];
- x[i4] = t1 + 2.0*x[i4];
- if (n4==1)
- continue;
- i1 += n8;
- i2 += n8;
- i3 += n8;
- i4 += n8;
- t1 = (x[i2]-x[i1])*SQRTHALF;
- t2 = (x[i4]+x[i3])*SQRTHALF;
- x[i1] += x[i2];
- x[i2] = x[i4]-x[i3];
- x[i3] = -2.0*(t2+t1);
- x[i4] = 2.0*(t1-t2);
- }
- is = (id<<1) - n2;
- id <<= 2;
- } while (is<n-1);
- dil = n/n2;
- a = dil;
- for (j=2;j<=n8;j++)
- {
- a3 = (a+(a<<1))&nminus;
- b = a*expand;
- b3 = a3*expand;
- cc1 = s_cos(b);
- ss1 = s_sin(b);
- cc3 = s_cos(b3);
- ss3 = s_sin(b3);
- a = (a+dil)&nminus;
- is = 0;
- id = n2<<1;
- do
- {
- for(i=is;i<n;i+=id)
- {
- i1 = i+j;
- i2 = i1+n4;
- i3 = i2+n4;
- i4 = i3+n4;
- i5 = i+n4-j+2;
- i6 = i5+n4;
- i7 = i6+n4;
- i8 = i7+n4;
- t1 = x[i1] - x[i6];
- x[i1] += x[i6];
- t2 = x[i5] - x[i2];
- x[i5] += x[i2];
- t3 = x[i8] + x[i3];
- x[i6] = x[i8] - x[i3];
- t4 = x[i4] + x[i7];
- x[i2] = x[i4] - x[i7];
- t5 = t1 - t4;
- t1 += t4;
- t4 = t2 - t3;
- t2 += t3;
- x[i3] = t5*cc1 + t4*ss1;
- x[i7] = -t4*cc1 + t5*ss1;
- x[i4] = t1*cc3 - t2*ss3;
- x[i8] = t2*cc3 + t1*ss3;
- }
- is = (id<<1) - n2;
- id <<= 2;
- } while(is<n-1);
- }
- }
- is = 1;
- id = 4;
- do
- {
- for (i0=is;i0<=n;i0+=id)
- {
- i1 = i0+1;
- e = x[i0];
- x[i0] = e + x[i1];
- x[i1] = e - x[i1];
- }
- is = (id<<1) - 1;
- id <<= 2;
- } while(is<n);
- scramble_real(z, n);
- e = 1/(double)n;
- for (i=0;i<n;i++)
- {
- z[i] *= e;
- }
-}
-
-
-void
-mul_hermitian(
- double *a,
- double *b,
- int n
-)
-{
- register int k, half = n>>1;
- register double aa, bb, am, bm;
-
- b[0] *= a[0];
- b[half] *= a[half];
- for (k=1;k<half;k++)
- {
- aa = a[k];
- bb = b[k];
- am = a[n-k];
- bm = b[n-k];
- b[k] = aa*bb - am*bm;
- b[n-k] = aa*bm + am*bb;
- }
-}
-
-
-void
-square_hermitian(
- double *b,
- int n
-)
-{
- register int k, half = n>>1;
- register double c, d;
-
- b[0] *= b[0];
- b[half] *= b[half];
- for (k=1;k<half;k++)
- {
- c = b[k];
- d = b[n-k];
- b[n-k] = 2.0*c*d;
- b[k] = (c+d)*(c-d);
- }
-}
-
-
-void
-giant_to_double
-(
- giant x,
- int sizex,
- double *z,
- int L
-)
-{
- register int j;
-
- for (j=sizex;j<L;j++)
- {
- z[j]=0.0;
- }
- for (j=0;j<sizex;j++)
- {
- z[j] = x->n[j];
- }
-}
-
-
-void
-gswap(
- giant *p,
- giant *q
-)
-{
- giant t;
-
- t = *p;
- *p = *q;
- *q = t;
-}
-
-
-void
-onestep(
- giant x,
- giant y,
- gmatrix A
-)
-/* Do one step of the euclidean algorithm and modify
- * the matrix A accordingly. */
-{
- giant s4 = popg();
-
- gtog(x,s4);
- gtog(y,x);
- gtog(s4,y);
- divg(x,s4);
- punch(s4,A);
- mulg(x,s4);
- subg(s4,y);
-
- pushg(1);
-}
-
-
-void
-mulvM(
- gmatrix A,
- giant x,
- giant y
-)
-/* Multiply vector by Matrix; changes x,y. */
-{
- giant s0 = popg(), s1 = popg();
-
- gtog(A->ur,s0);
- gtog( A->lr,s1);
- dotproduct(x,y,A->ul,s0);
- dotproduct(x,y,A->ll,s1);
- gtog(s0,x);
- gtog(s1,y);
-
- pushg(2);
-}
-
-
-void
-mulmM(
- gmatrix A,
- gmatrix B
-)
-/* Multiply matrix by Matrix; changes second matrix. */
-{
- giant s0 = popg();
- giant s1 = popg();
- giant s2 = popg();
- giant s3 = popg();
-
- gtog(B->ul,s0);
- gtog(B->ur,s1);
- gtog(B->ll,s2);
- gtog(B->lr,s3);
- dotproduct(A->ur,A->ul,B->ll,s0);
- dotproduct(A->ur,A->ul,B->lr,s1);
- dotproduct(A->ll,A->lr,B->ul,s2);
- dotproduct(A->ll,A->lr,B->ur,s3);
- gtog(s0,B->ul);
- gtog(s1,B->ur);
- gtog(s2,B->ll);
- gtog(s3,B->lr);
-
- pushg(4);
-}
-
-
-void
-writeM(
- gmatrix A
-)
-{
- printf(" ul:");
- gout(A->ul);
- printf(" ur:");
- gout(A->ur);
- printf(" ll:");
- gout(A->ll);
- printf(" lr:");
- gout(A->lr);
-}
-
-
-void
-punch(
- giant q,
- gmatrix A
-)
-/* Multiply the matrix A on the left by [0,1,1,-q]. */
-{
- giant s0 = popg();
-
- gtog(A->ll,s0);
- mulg(q,A->ll);
- gswap(&A->ul,&A->ll);
- subg(A->ul,A->ll);
- gtog(s0,A->ul);
- gtog(A->lr,s0);
- mulg(q,A->lr);
- gswap(&A->ur,&A->lr);
- subg(A->ur,A->lr);
- gtog(s0,A->ur);
-
- pushg(1);
-}
-
-
-static void
-dotproduct(
- giant a,
- giant b,
- giant c,
- giant d
-)
-/* Replace last argument with the dot product of two 2-vectors. */
-{
- giant s4 = popg();
-
- gtog(c,s4);
- mulg(a, s4);
- mulg(b,d);
- addg(s4,d);
-
- pushg(1);
-}
-
-
-void
-ggcd(
- giant xx,
- giant yy
-)
-/* A giant gcd. Modifies its arguments. */
-{
- giant x = popg(), y = popg();
- gmatrix A = newgmatrix();
-
- gtog(xx,x); gtog(yy,y);
- for(;;)
- {
- fix(&x,&y);
- if (bitlen(y) <= GCDLIMIT )
- break;
- A->ul = popg();
- A->ur = popg();
- A->ll = popg();
- A->lr = popg();
- itog(1,A->ul);
- itog(0,A->ur);
- itog(0,A->ll);
- itog(1,A->lr);
- hgcd(0,x,y,A);
- mulvM(A,x,y);
- pushg(4);
- fix(&x,&y);
- if (bitlen(y) <= GCDLIMIT )
- break;
- modg(y,x);
- gswap(&x,&y);
- }
- bgcdg(x,y);
- gtog(y,yy);
- pushg(2);
- free(A);
-}
-
-
-void
-fix(
- giant *p,
- giant *q
-)
-/* Insure that x > y >= 0. */
-{
- if( gsign(*p) < 0 )
- negg(*p);
- if( gsign(*q) < 0 )
- negg(*q);
- if( gcompg(*p,*q) < 0 )
- gswap(p,q);
-}
-
-
-void
-hgcd(
- int n,
- giant xx,
- giant yy,
- gmatrix A
-)
-/* hgcd(n,x,y,A) chops n bits off x and y and computes th
- * 2 by 2 matrix A such that A[x y] is the pair of terms
- * in the remainder sequence starting with x,y that is
- * half the size of x. Note that the argument A is modified
- * but that the arguments xx and yy are left unchanged.
- */
-{
- giant x, y;
-
- if (isZero(yy))
- return;
-
- x = popg();
- y = popg();
- gtog(xx,x);
- gtog(yy,y);
- gshiftright(n,x);
- gshiftright(n,y);
- if (bitlen(x) <= INTLIMIT )
- {
- shgcd(gtoi(x),gtoi(y),A);
- }
- else
- {
- gmatrix B = newgmatrix();
- int m = bitlen(x)/2;
-
- hgcd(m,x,y,A);
- mulvM(A,x,y);
- if (gsign(x) < 0)
- {
- negg(x); negg(A->ul); negg(A->ur);
- }
- if (gsign(y) < 0)
- {
- negg(y); negg(A->ll); negg(A->lr);
- }
- if (gcompg(x,y) < 0)
- {
- gswap(&x,&y);
- gswap(&A->ul,&A->ll);
- gswap(&A->ur,&A->lr);
- }
- if (!isZero(y))
- {
- onestep(x,y,A);
- m /= 2;
- B->ul = popg();
- B->ur = popg();
- B->ll = popg();
- B->lr = popg();
- itog(1,B->ul);
- itog(0,B->ur);
- itog(0,B->ll);
- itog(1,B->lr);
- hgcd(m,x,y,B);
- mulmM(B,A);
- pushg(4);
- }
- free(B);
- }
- pushg(2);
-}
-
-
-void
-shgcd(
- register int x,
- register int y,
- gmatrix A
-)
-/*
- * Do a half gcd on the integers a and b, putting the result in A
- * It is fairly easy to use the 2 by 2 matrix description of the
- * extended Euclidean algorithm to prove that the quantity q*t
- * never overflows.
- */
-{
- register int q, t, start = x;
- int Aul = 1, Aur = 0, All = 0, Alr = 1;
-
- while (y != 0 && y > start/y)
- {
- q = x/y;
- t = y;
- y = x%y;
- x = t;
- t = All;
- All = Aul-q*t;
- Aul = t;
- t = Alr;
- Alr = Aur-q*t;
- Aur = t;
- }
- itog(Aul,A->ul);
- itog(Aur,A->ur);
- itog(All,A->ll);
- itog(Alr,A->lr);
-}