source: src/main/java/agents/anac/y2019/harddealer/math3/primes/PollardRho.java

Last change on this file was 204, checked in by Katsuhide Fujita, 5 years ago

Fixed errors of ANAC2019 agents

  • Property svn:executable set to *
File size: 5.5 KB
Line 
1/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17package agents.anac.y2019.harddealer.math3.primes;
18
19import java.util.ArrayList;
20import java.util.List;
21
22import agents.anac.y2019.harddealer.math3.util.FastMath;
23
24/**
25 * Implementation of the Pollard's rho factorization algorithm.
26 * @since 3.2
27 */
28class PollardRho {
29
30 /**
31 * Hide utility class.
32 */
33 private PollardRho() {
34 }
35
36 /**
37 * Factorization using Pollard's rho algorithm.
38 * @param n number to factors, must be > 0
39 * @return the list of prime factors of n.
40 */
41 public static List<Integer> primeFactors(int n) {
42 final List<Integer> factors = new ArrayList<Integer>();
43
44 n = SmallPrimes.smallTrialDivision(n, factors);
45 if (1 == n) {
46 return factors;
47 }
48
49 if (SmallPrimes.millerRabinPrimeTest(n)) {
50 factors.add(n);
51 return factors;
52 }
53
54 int divisor = rhoBrent(n);
55 factors.add(divisor);
56 factors.add(n / divisor);
57 return factors;
58 }
59
60 /**
61 * Implementation of the Pollard's rho factorization algorithm.
62 * <p>
63 * This implementation follows the paper "An improved Monte Carlo factorization algorithm"
64 * by Richard P. Brent. This avoids the triple computation of f(x) typically found in Pollard's
65 * rho implementations. It also batches several gcd computation into 1.
66 * <p>
67 * The backtracking is not implemented as we deal only with semi-primes.
68 *
69 * @param n number to factor, must be semi-prime.
70 * @return a prime factor of n.
71 */
72 static int rhoBrent(final int n) {
73 final int x0 = 2;
74 final int m = 25;
75 int cst = SmallPrimes.PRIMES_LAST;
76 int y = x0;
77 int r = 1;
78 do {
79 int x = y;
80 for (int i = 0; i < r; i++) {
81 final long y2 = ((long) y) * y;
82 y = (int) ((y2 + cst) % n);
83 }
84 int k = 0;
85 do {
86 final int bound = FastMath.min(m, r - k);
87 int q = 1;
88 for (int i = -3; i < bound; i++) { //start at -3 to ensure we enter this loop at least 3 times
89 final long y2 = ((long) y) * y;
90 y = (int) ((y2 + cst) % n);
91 final long divisor = FastMath.abs(x - y);
92 if (0 == divisor) {
93 cst += SmallPrimes.PRIMES_LAST;
94 k = -m;
95 y = x0;
96 r = 1;
97 break;
98 }
99 final long prod = divisor * q;
100 q = (int) (prod % n);
101 if (0 == q) {
102 return gcdPositive(FastMath.abs((int) divisor), n);
103 }
104 }
105 final int out = gcdPositive(FastMath.abs(q), n);
106 if (1 != out) {
107 return out;
108 }
109 k += m;
110 } while (k < r);
111 r = 2 * r;
112 } while (true);
113 }
114
115 /**
116 * Gcd between two positive numbers.
117 * <p>
118 * Gets the greatest common divisor of two numbers, using the "binary gcd" method,
119 * which avoids division and modulo operations. See Knuth 4.5.2 algorithm B.
120 * This algorithm is due to Josef Stein (1961).
121 * </p>
122 * Special cases:
123 * <ul>
124 * <li>The result of {@code gcd(x, x)}, {@code gcd(0, x)} and {@code gcd(x, 0)} is the value of {@code x}.</li>
125 * <li>The invocation {@code gcd(0, 0)} is the only one which returns {@code 0}.</li>
126 * </ul>
127 *
128 * @param a first number, must be &ge; 0
129 * @param b second number, must be &ge; 0
130 * @return gcd(a,b)
131 */
132 static int gcdPositive(int a, int b){
133 // both a and b must be positive, it is not checked here
134 // gdc(a,0) = a
135 if (a == 0) {
136 return b;
137 } else if (b == 0) {
138 return a;
139 }
140
141 // make a and b odd, keep in mind the common power of twos
142 final int aTwos = Integer.numberOfTrailingZeros(a);
143 a >>= aTwos;
144 final int bTwos = Integer.numberOfTrailingZeros(b);
145 b >>= bTwos;
146 final int shift = FastMath.min(aTwos, bTwos);
147
148 // a and b >0
149 // if a > b then gdc(a,b) = gcd(a-b,b)
150 // if a < b then gcd(a,b) = gcd(b-a,a)
151 // so next a is the absolute difference and next b is the minimum of current values
152 while (a != b) {
153 final int delta = a - b;
154 b = FastMath.min(a, b);
155 a = FastMath.abs(delta);
156 // for speed optimization:
157 // remove any power of two in a as b is guaranteed to be odd throughout all iterations
158 a >>= Integer.numberOfTrailingZeros(a);
159 }
160
161 // gcd(a,a) = a, just "add" the common power of twos
162 return a << shift;
163 }
164}
Note: See TracBrowser for help on using the repository browser.