Advertisement
arch239

Алгоритм Тонелли — Шенкса

Oct 13th, 2017
136
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 3.17 KB | None | 0 0
  1. import java.math.BigInteger;
  2.  
  3. import static java.math.BigInteger.ONE;
  4. import static java.math.BigInteger.ZERO;
  5. import static java.math.BigInteger.valueOf;
  6.  
  7. public class TonelliShanksAlgorithm {
  8.  
  9.     static final BigInteger TWO = valueOf(2);
  10.     static final BigInteger THREE = valueOf(3);
  11.     static final BigInteger FOUR = valueOf(4);
  12.  
  13.     public static void main(String[] args) {
  14.         printRoots(103, 1789);
  15.         printRoots("24296403966", "32416188697");
  16.         printRoots("84235199442121369408907697", "241573142393627673576957439049");
  17.         printRoots("6706901388311723110433121899414477003899", "45994811347886846310221728895223034301839");
  18.     }
  19.  
  20.     static void printRoots(String n, String p) {
  21.         printRoots(new BigInteger(n), new BigInteger(p));
  22.     }
  23.  
  24.     static void printRoots(int n, int p) {
  25.         printRoots(valueOf(n), valueOf(p));
  26.     }
  27.  
  28.     static void printRoots(BigInteger n, BigInteger p) {
  29.         BigInteger a = getRoot(n, p);
  30.         a = a.min(p.subtract(a));
  31.         System.out.println(a + ", " + p.subtract(a));
  32.     }
  33.  
  34.     static BigInteger getRoot(BigInteger n, BigInteger p) {
  35.         BigInteger s = ZERO;
  36.         BigInteger q = p.subtract(ONE);
  37.  
  38.         while (true) {
  39.             BigInteger[] quotientAndRem = q.divideAndRemainder(TWO);
  40.  
  41.             if (quotientAndRem[1].equals(ZERO)) {
  42.                 q = quotientAndRem[0];
  43.                 s = s.add(ONE);
  44.             } else
  45.                 break;
  46.         }
  47.  
  48.         if (s.equals(ONE))
  49.             return n.modPow(p.add(ONE).divide(FOUR), p);
  50.  
  51.         BigInteger z = TWO;
  52.         for (; ; z = z.add(ONE))
  53.             if (jacobiSymbol(z, p) == -1)
  54.                 break;
  55.  
  56.         BigInteger c = z.modPow(q, p);
  57.         BigInteger r = n.modPow(q.add(ONE).divide(TWO), p);
  58.         BigInteger t = n.modPow(q, p);
  59.         BigInteger m = s;
  60.  
  61.         while (true) {
  62.             if (t.equals(ONE))
  63.                 return r;
  64.  
  65.             int i = 1;
  66.             BigInteger d = t;
  67.             for (; i < m.intValue(); i++) {
  68.                 d = d.multiply(d).mod(p);
  69.                 if (d.equals(ONE))
  70.                     break;
  71.             }
  72.  
  73.             BigInteger degree = TWO.modPow(m.subtract(valueOf(i + 1)), p.subtract(ONE));
  74.             BigInteger b = c.modPow(degree, p);
  75.             r = r.multiply(b).mod(p);
  76.             c = b.multiply(b).mod(p);
  77.             t = t.multiply(c).mod(p);
  78.             m = valueOf(i);
  79.         }
  80.     }
  81.  
  82.     static int jacobiSymbol(BigInteger a, BigInteger n) {
  83.         if (a.equals(ZERO))
  84.             return (n.equals(ONE)) ? 1 : 0;
  85.  
  86.         if (a.equals(TWO))
  87.             switch (n.mod(valueOf(8)).intValue()) {
  88.                 case 1:
  89.                 case 7:
  90.                     return 1;
  91.                 case 3:
  92.                 case 5:
  93.                     return -1;
  94.             }
  95.  
  96.         if (a.compareTo(n) >= 0)
  97.             return jacobiSymbol(a.mod(n), n);
  98.  
  99.         if (a.mod(TWO).equals(ZERO))
  100.             return jacobiSymbol(TWO, n) * jacobiSymbol(a.divide(TWO), n);
  101.  
  102.         return (a.mod(FOUR).equals(THREE) && n.mod(FOUR).equals(THREE))
  103.                 ? -jacobiSymbol(n, a) : jacobiSymbol(n, a);
  104.     }
  105. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement