Artifact 1b8b81febb52f905b4641f967faaafcb98e6ae325ec2cec0b70510078b08b501:
- Executable file
r37/packages/alg/smallmod.red
— part of check-in
[f2fda60abd]
at
2011-09-02 18:13:33
on branch master
— Some historical releases purely for archival purposes
git-svn-id: https://svn.code.sf.net/p/reduce-algebra/code/trunk/historical@1375 2bfe0521-f11c-4a00-b80e-6202646ff360 (user: arthurcnorman@users.sourceforge.net, size: 3030) [annotate] [blame] [check-ins using] [more...]
- Executable file
r38/packages/alg/smallmod.red
— part of check-in
[f2fda60abd]
at
2011-09-02 18:13:33
on branch master
— Some historical releases purely for archival purposes
git-svn-id: https://svn.code.sf.net/p/reduce-algebra/code/trunk/historical@1375 2bfe0521-f11c-4a00-b80e-6202646ff360 (user: arthurcnorman@users.sourceforge.net, size: 3030) [annotate] [blame] [check-ins using]
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;