12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970 |
- #include "BigIntegerAlgorithms.hh"
- BigUnsigned gcd(BigUnsigned a, BigUnsigned b) {
- BigUnsigned trash;
- // Neat in-place alternating technique.
- for (;;) {
- if (b.isZero())
- return a;
- a.divideWithRemainder(b, trash);
- if (a.isZero())
- return b;
- b.divideWithRemainder(a, trash);
- }
- }
- void extendedEuclidean(BigInteger m, BigInteger n,
- BigInteger &g, BigInteger &r, BigInteger &s) {
- if (&g == &r || &g == &s || &r == &s)
- throw "BigInteger extendedEuclidean: Outputs are aliased";
- BigInteger r1(1), s1(0), r2(0), s2(1), q;
- /* Invariants:
- * r1*m(orig) + s1*n(orig) == m(current)
- * r2*m(orig) + s2*n(orig) == n(current) */
- for (;;) {
- if (n.isZero()) {
- r = r1; s = s1; g = m;
- return;
- }
- // Subtract q times the second invariant from the first invariant.
- m.divideWithRemainder(n, q);
- r1 -= q*r2; s1 -= q*s2;
- if (m.isZero()) {
- r = r2; s = s2; g = n;
- return;
- }
- // Subtract q times the first invariant from the second invariant.
- n.divideWithRemainder(m, q);
- r2 -= q*r1; s2 -= q*s1;
- }
- }
- BigUnsigned modinv(const BigInteger &x, const BigUnsigned &n) {
- BigInteger g, r, s;
- extendedEuclidean(x, n, g, r, s);
- if (g == 1)
- // r*x + s*n == 1, so r*x === 1 (mod n), so r is the answer.
- return (r % n).getMagnitude(); // (r % n) will be nonnegative
- else
- throw "BigInteger modinv: x and n have a common factor";
- }
- BigUnsigned modexp(const BigInteger &base, const BigUnsigned &exponent,
- const BigUnsigned &modulus) {
- BigUnsigned ans = 1, base2 = (base % modulus).getMagnitude();
- BigUnsigned::Index i = exponent.bitLength();
- // For each bit of the exponent, most to least significant...
- while (i > 0) {
- i--;
- // Square.
- ans *= ans;
- ans %= modulus;
- // And multiply if the bit is a 1.
- if (exponent.getBit(i)) {
- ans *= base2;
- ans %= modulus;
- }
- }
- return ans;
- }
|