/// <summary> /// Extended GCD algorithm. Finds U and V, that A*U + B*V = GCD(A, B) /// </summary> /// <param name="inputA">Number A</param> /// <param name="inputB">Number B</param> /// <param name="U">U</param> /// <param name="V">V</param> /// <returns>GCD of A and B</returns> public static SLongIntB eXtendedGCD(SLongIntB inputA, SLongIntB inputB, out SLongIntB U, out SLongIntB V) { // GCD == A*U + B*V SLongIntB A = inputA; SLongIntB B = inputB; U = (SLongIntB)1; SLongIntB D = new SLongIntB(A); if (B.IsZero()) { V = (SLongIntB)0; return D; } SLongIntB v1 = (SLongIntB)0; SLongIntB v3 = new SLongIntB(B); SLongIntB Q = null; SLongIntB t3 = null; SLongIntB t1 = null; while (!v3.IsZero()) { LongMath.Divide(D, v3, out Q, out t3); t1 = U - (Q*v1); U.Assign(v1); D.Assign(v3); v1.Assign(t1); v3.Assign(t3); } V = D - (U*A); V /= B; return D; }
/// <summary> /// Calculates Jacobi symbol for long numbers A and B - (A/B) /// </summary> /// <param name="A"></param> /// <param name="B"></param> /// <returns></returns> public static int JacobiSymbol(SLongIntB a, SLongIntB b) { if (b.IsZero()) { if (a == 1 || a == -1) return 1; else return 0; } if (LongMath.IsEven(a) && LongMath.IsEven(b)) return 0; SLongIntB A = new SLongIntB(a); SLongIntB B = new SLongIntB(b); sbyte[] mods = new sbyte[] { 0, 1, 0, -1, 0, -1, 0, 1 }; int v = 0; SelfTwoFact(B, out v); int k = 1; if (v % 2 == 1) k = mods[A[0] & 7]; LongMath.SelfAbs(B); if (A < 0) k = -k; while (A > 0) { SelfTwoFact(A, out v); if (v % 2 == 1) k = mods[B[0] & 7] * k; if ((A[0] & B[0] & 2) != 0) k = -k; SLongIntB r = LongMath.Abs(A); A.Assign(B % r); B.Assign(r); } if (B > 1) return 0; else return k; }
/// <summary> /// Uses extended GCD Algorithm to find inverted by modulo element /// </summary> /// <param name="A">Number</param> /// <param name="N">Modulo</param> /// <param name="U">Inverted element. Can be less, than zero. /// To get always positive number, use eXGCDInvernedSafe instead.</param> /// <returns>GCD of A and N</returns> public static SLongIntB eXGCDInverted(SLongIntB A, SLongIntB N, out SLongIntB U) { // 1 == A*U + N*V if (A.IsZero()) { U = new SLongIntB(); if (A.IsZero()) return new SLongIntB(N); else return new SLongIntB(A); } U = (SLongIntB)1; SLongIntB G = new SLongIntB(A); SLongIntB v1 = (SLongIntB)0; SLongIntB v3 = new SLongIntB(N); SLongIntB Q = null; SLongIntB t3 = null; SLongIntB t1 = null; while (!v3.IsZero()) { LongMath.Divide(G, v3, out Q, out t3); t1 = U - (Q*v1); U.Assign(v1); G.Assign(v3); v1.Assign(t1); v3.Assign(t3); } return G; }