smallmod.red 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. module smallmod; % Small integer modular arithmetic used in factorizer.
  2. % Author: Arthur C. Norman.
  3. % Note: when balanced_mod is on, the results here are not always in
  4. % range. *modular2f is used to correct this.
  5. fluid '(!*balanced_mod current!-modulus modulus!/2);
  6. global '(largest!-small!-modulus);
  7. symbolic procedure set!-modulus p; set!-general!-modulus p;
  8. symbolic procedure set!-small!-modulus p;
  9. begin
  10. scalar previous!-modulus;
  11. if p>largest!-small!-modulus
  12. then rerror(alg,9,list("Overlarge modulus",p,"being used"));
  13. previous!-modulus:=current!-modulus;
  14. current!-modulus:=p;
  15. modulus!/2 := p/2;
  16. return previous!-modulus
  17. end;
  18. smacro procedure modular!-plus(a,b);
  19. begin scalar result;
  20. result:=a #+ b;
  21. if not(result #< current!-modulus) then
  22. result:=result #- current!-modulus;
  23. return result
  24. end;
  25. smacro procedure modular!-difference(a,b);
  26. begin scalar result;
  27. result:=a #- b;
  28. if iminusp result then result:=result #+ current!-modulus;
  29. return result
  30. end;
  31. symbolic procedure modular!-number a;
  32. begin
  33. if not atom a then typerr(a,"integer in modular-number");
  34. a:=remainder(a,current!-modulus);
  35. if iminusp a then a:=a #+ current!-modulus;
  36. return a
  37. end;
  38. smacro procedure modular!-times(a,b);
  39. remainder(a*b,current!-modulus);
  40. symbolic procedure modular!-reciprocal a;
  41. if !*balanced_mod and a<0
  42. then reciprocal!-by!-gcd(current!-modulus,
  43. a #+ current!-modulus,0,1)
  44. else reciprocal!-by!-gcd(current!-modulus,a,0,1);
  45. symbolic procedure reciprocal!-by!-gcd(a,b,x,y);
  46. %On input A and B should be coprime. This routine then
  47. %finds X and Y such that A*X+B*Y=1, and returns the value Y
  48. %on input A > B;
  49. if b=0 then rerror(alg,10,"Invalid modular division")
  50. else if b=1 then if iminusp y then y #+ current!-modulus else y
  51. else begin scalar w;
  52. %N.B. Invalid modular division is either:
  53. % a) attempt to divide by zero directly
  54. % b) modulus is not prime, and input is not
  55. % coprime with it;
  56. w:= a #/ b; %Truncated integer division;
  57. return reciprocal!-by!-gcd(b,a #- b #* w,
  58. y,x #- y #* w)
  59. end;
  60. smacro procedure modular!-quotient(a,b);
  61. modular!-times(a,modular!-reciprocal b);
  62. smacro procedure modular!-minus a;
  63. if a=0 then a else current!-modulus #- a;
  64. symbolic procedure modular!-expt(a,n);
  65. % Computes a**n modulo current-modulus. Uses Fermat's Little
  66. % Theorem where appropriate for a prime modulus.
  67. if n=0 then 1
  68. else if n=1 then a
  69. else if n>=current!-modulus-1 and primep current!-modulus
  70. then modular!-expt(a,remainder(n,current!-modulus-1))
  71. else begin scalar x;
  72. x:=modular!-expt(a,n/2);
  73. x:=modular!-times(x,x);
  74. if not(remainder(n,2)=0) then x:=modular!-times(x,a);
  75. return x
  76. end;
  77. symbolic set!-modulus(1) ; % forces everything into a standard state.
  78. endmodule;
  79. end;