BigIntegerAlgorithms.cc 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. #include "BigIntegerAlgorithms.hh"
  2. BigUnsigned gcd(BigUnsigned a, BigUnsigned b) {
  3. BigUnsigned trash;
  4. // Neat in-place alternating technique.
  5. for (;;) {
  6. if (b.isZero())
  7. return a;
  8. a.divideWithRemainder(b, trash);
  9. if (a.isZero())
  10. return b;
  11. b.divideWithRemainder(a, trash);
  12. }
  13. }
  14. void extendedEuclidean(BigInteger m, BigInteger n,
  15. BigInteger &g, BigInteger &r, BigInteger &s) {
  16. if (&g == &r || &g == &s || &r == &s)
  17. throw "BigInteger extendedEuclidean: Outputs are aliased";
  18. BigInteger r1(1), s1(0), r2(0), s2(1), q;
  19. /* Invariants:
  20. * r1*m(orig) + s1*n(orig) == m(current)
  21. * r2*m(orig) + s2*n(orig) == n(current) */
  22. for (;;) {
  23. if (n.isZero()) {
  24. r = r1; s = s1; g = m;
  25. return;
  26. }
  27. // Subtract q times the second invariant from the first invariant.
  28. m.divideWithRemainder(n, q);
  29. r1 -= q*r2; s1 -= q*s2;
  30. if (m.isZero()) {
  31. r = r2; s = s2; g = n;
  32. return;
  33. }
  34. // Subtract q times the first invariant from the second invariant.
  35. n.divideWithRemainder(m, q);
  36. r2 -= q*r1; s2 -= q*s1;
  37. }
  38. }
  39. BigUnsigned modinv(const BigInteger &x, const BigUnsigned &n) {
  40. BigInteger g, r, s;
  41. extendedEuclidean(x, n, g, r, s);
  42. if (g == 1)
  43. // r*x + s*n == 1, so r*x === 1 (mod n), so r is the answer.
  44. return (r % n).getMagnitude(); // (r % n) will be nonnegative
  45. else
  46. throw "BigInteger modinv: x and n have a common factor";
  47. }
  48. BigUnsigned modexp(const BigInteger &base, const BigUnsigned &exponent,
  49. const BigUnsigned &modulus) {
  50. BigUnsigned ans = 1, base2 = (base % modulus).getMagnitude();
  51. BigUnsigned::Index i = exponent.bitLength();
  52. // For each bit of the exponent, most to least significant...
  53. while (i > 0) {
  54. i--;
  55. // Square.
  56. ans *= ans;
  57. ans %= modulus;
  58. // And multiply if the bit is a 1.
  59. if (exponent.getBit(i)) {
  60. ans *= base2;
  61. ans %= modulus;
  62. }
  63. }
  64. return ans;
  65. }