123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100 |
- module smallmod; % Small integer modular arithmetic used in factorizer.
- % Author: Arthur C. Norman.
- % Note: when balanced_mod is on, the results here are not always in
- % range. *modular2f is used to correct this.
- fluid '(!*balanced_mod current!-modulus modulus!/2);
- global '(largest!-small!-modulus);
- symbolic procedure set!-modulus p; set!-general!-modulus p;
- symbolic procedure set!-small!-modulus p;
- begin
- scalar previous!-modulus;
- if p>largest!-small!-modulus
- then rerror(alg,9,list("Overlarge modulus",p,"being used"));
- previous!-modulus:=current!-modulus;
- current!-modulus:=p;
- modulus!/2 := p/2;
- return previous!-modulus
- end;
- smacro procedure modular!-plus(a,b);
- begin scalar result;
- result:=a #+ b;
- if not(result #< current!-modulus) then
- result:=result #- current!-modulus;
- return result
- end;
- smacro procedure modular!-difference(a,b);
- begin scalar result;
- result:=a #- b;
- if iminusp result then result:=result #+ current!-modulus;
- return result
- end;
- symbolic procedure modular!-number a;
- begin
- if not atom a then typerr(a,"integer in modular-number");
- a:=remainder(a,current!-modulus);
- if iminusp a then a:=a #+ current!-modulus;
- return a
- end;
- smacro procedure modular!-times(a,b);
- remainder(a*b,current!-modulus);
- symbolic procedure modular!-reciprocal a;
- if !*balanced_mod and a<0
- then reciprocal!-by!-gcd(current!-modulus,
- a #+ current!-modulus,0,1)
- else reciprocal!-by!-gcd(current!-modulus,a,0,1);
- symbolic procedure reciprocal!-by!-gcd(a,b,x,y);
- %On input A and B should be coprime. This routine then
- %finds X and Y such that A*X+B*Y=1, and returns the value Y
- %on input A > B;
- if b=0 then rerror(alg,10,"Invalid modular division")
- else if b=1 then if iminusp y then y #+ current!-modulus else y
- else begin scalar w;
- %N.B. Invalid modular division is either:
- % a) attempt to divide by zero directly
- % b) modulus is not prime, and input is not
- % coprime with it;
- w:= a #/ b; %Truncated integer division;
- return reciprocal!-by!-gcd(b,a #- b #* w,
- y,x #- y #* w)
- end;
- smacro procedure modular!-quotient(a,b);
- modular!-times(a,modular!-reciprocal b);
- smacro procedure modular!-minus a;
- if a=0 then a else current!-modulus #- a;
- symbolic procedure modular!-expt(a,n);
- % Computes a**n modulo current-modulus. Uses Fermat's Little
- % Theorem where appropriate for a prime modulus.
- if n=0 then 1
- else if n=1 then a
- else if n>=current!-modulus-1 and primep current!-modulus
- then modular!-expt(a,remainder(n,current!-modulus-1))
- else begin scalar x;
- x:=modular!-expt(a,n/2);
- x:=modular!-times(x,x);
- if not(remainder(n,2)=0) then x:=modular!-times(x,a);
- return x
- end;
- symbolic set!-modulus(1) ; % forces everything into a standard state.
- endmodule;
- end;
|