Zielony Smok - logo witryny

Kongruencje (Java)

Podstawy teoretyczne kongruencji były omówione wcześniej. A oto zestaw klas Java pozwalających pracować z kongruencjami.

Klasy

Klasa Congruence
package congruence;

public final class Congruence {
    private final long a;
    private final long b;
    private final long m;

    public Congruence(long a, long b, long m) {
        if (((a - b) % m) == 0) {
            this.a = a;
            this.b = b;
            this.m = m;
        } else {
            throw new ArithmeticException("Dane nieprawidłowe");
        }
    }

    public long getA() {
        return a;
    }

    public long getB() {
        return b;
    }

    public long getM() {
        return m;
    }

    @Override
    public int hashCode() {
        return 3 * Long.valueOf(a).hashCode() + 5 * Long.valueOf(b).hashCode() + 7 * Long.valueOf(m).hashCode();
    }

    @Override
    public boolean equals(Object o) {
        if (o == null) {
            return false;
        }
        if (this.getClass() != o.getClass()) {
            return false;
        }
        Congruence other = (Congruence) o;
        return (this.a == other.getA()) && (this.b == other.getB()) && (this.m == other.getM());
    }

    @Override
    public String toString() {
        return a + "\u2261" + b + "(mod " + m + ")";
    }

    public static Congruence add(Congruence cong1, Congruence cong2) {
        if (cong1.getM() == cong2.getM()) {
            return new Congruence(Math.addExact(cong1.getA(), cong2.getA()), Math.addExact(cong1.getB(), cong2.getB()), cong1.getM());
        }
        return null;
    }

    public static Congruence sub(Congruence cong1, Congruence cong2) {
        if (cong1.getM() == cong2.getM()) {
            return new Congruence(Math.subtractExact(cong1.getA(), cong2.getA()), Math.subtractExact(cong1.getB(), cong2.getB()), cong1.getM());
        }
        return null;
    }

    public static Congruence mult(Congruence cong1, Congruence cong2) {
        if (cong1.getM() == cong2.getM()) {
            return new Congruence(Math.multiplyExact(cong1.getA(), cong2.getA()), Math.multiplyExact(cong1.getB(), cong2.getB()), cong1.getM());
        }
        return null;
    }

    public static Congruence mult(Congruence cong, long num) {
        return new Congruence(Math.multiplyExact(cong.getA(), num), Math.multiplyExact(cong.getB(), num), cong.getM());
    }

    public static Congruence pow(Congruence cong, int exp) {
        return new Congruence(ModUtil.powExact(cong.getA(), Math.abs(exp)), ModUtil.powExact(cong.getB(), Math.abs(exp)), cong.getM());
    }

    public static Congruence div(Congruence kong, long num) {
        long a = kong.getA();
        long b = kong.getB();
        long m = kong.getM();
        if ((a % num == 0) && (b % num == 0) && (m % num == 0)) {
            return new Congruence(a / num, b / num, m / num);
        } else {
            throw new ArithmeticException("'Dane nieprawidłowe");
        }
    }
}
Klasa ModUtil
package congruence;

public class ModUtil {
    private ModUtil() {
    }

    /**
     * Zwraca resztę z dzielenia w znaczeniu kongruencji.
     * Różni się od % tym, że:
     * 1) nie przyjmuje ujemnego modulusa
     * 2) jeśli dzielna jest ujemna, a więc i reszta % jest ujemna zwraca resztę %
     * powiększona o modulus.
     * -10 % 3 = -1
     * mod(-10, 3) = -1 + 3 = 2
     *
     * @param dzielna - dzielna
     * @param modulus - dzielnik
     * @return - zwraca resztę z dzielenia w znaczeniu kongruencji
     */
    public static long mod(long dzielna, long modulus) {
        if (modulus <= 0) {
            throw new ArithmeticException("Nieprawidłowy argument");
        }
        long i = dzielna % modulus;
        if (i < 0) {
            i = (modulus + i);
        }
        return i;
    }

    public static long modAdd(long a, long b, long modulus) {
        return mod(Math.addExact(a, b), modulus);
    }
    public static long modSub(long a, long b, long modulus) {
        return mod(Math.subtractExact(a, b), modulus);
    }
    public static long modMult(long a, long b, long modulus) {
        return mod(Math.multiplyExact(a, b), modulus);
    }
    public static long powExact(long a, long exp) {
        if (exp < 0) {
            throw new ArithmeticException("Wykładnik mniejszy od 0");
        }
        long w = 1L;
        while (exp > 0) {
            if ((exp & 1) == 1) {
                w = Math.multiplyExact(w, Math.multiplyExact(w, a));
            } else {
                w = Math.multiplyExact(w, w);
            }
            exp >>= 1;
        }
        return w;
    }

    public static long modPow(long a, long exp, long modulus) {
        return mod(powExact(a, exp), modulus);
    }
}
Klasa CongruenceTestAdd
package congruence;

public class CongruenceTestAdd {
    public static void main(String[] args) {
        Congruence k1 = new Congruence(12, 7, 5);
        Congruence k2 = new Congruence(27, 42, 5);
        System.out.println(Congruence.add(k1, k2));
    }
}

Po uruchomieniu na konsoli zobaczymy:

39≡49(mod 5)
Klasa CongruenceTestSubtract
package congruence;

public class CongruenceTestSubtract {
    public static void main(String[] args) {
        Congruence k3 = new Congruence(15, 6, 9);
        Congruence k4 = new Congruence(12, 21, 9);
        System.out.println(Congruence.sub(k3, k4));
    }
}

Po uruchomieniu na konsoli zobaczymy:

3≡-15(mod 9)
Klasa CongruenceTestMult
package congruence;

public class CongruenceTestMult {
    public static void main(String[] args) {
        Congruence k5 = new Congruence(15, 8, 7);
        Congruence k6 = new Congruence(3, 10, 7);
        System.out.println(Congruence.mult(k5, k6));
        //-
        Congruence k7 = new Congruence(5, 2, 3);
        long num1 = 3;
        System.out.println(Congruence.mult(k7, num1));
    }
}

Po uruchomieniu na konsoli zobaczymy:

45≡80(mod 7)
15≡6(mod 3)
Klasa CongruenceTestPow
package congruence;

public class CongruenceTestPow {
    public static void main(String[] args) {

        Congruence k8 = new Congruence(5, 2, 3);
        System.out.println(k8);
        int exp2 = 3;
        System.out.println(Congruence.pow(k8, exp2));
    }
}

Po uruchomieniu na konsoli zobaczymy:

5≡2(mod 3)
125≡8(mod 3)

Klasa CongruenceTestDiv
package congruence;

public class CongruenceTestDiv {
    public static void main(String[] args) {

        Congruence k9 = new Congruence(15, 6, 9);
        int num2 = 3;
        System.out.println(Congruence.div(k9, 3));
    }
}

Po uruchomieniu na konsoli zobaczymy:

5≡2(mod 3)