Skip to content

Commit 631b536

Browse files
committed
improve TDiv63*.searchFactors(), used by TinyEcm64*
1 parent cd2a499 commit 631b536

File tree

7 files changed

+72
-36
lines changed

7 files changed

+72
-36
lines changed

src/main/java/de/tilman_neumann/jml/factor/ecm/TinyEcm64.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
import de.tilman_neumann.jml.factor.FactorAlgorithm;
4444
import de.tilman_neumann.jml.factor.base.FactorArguments;
4545
import de.tilman_neumann.jml.factor.base.FactorResult;
46-
import de.tilman_neumann.jml.factor.tdiv.TDiv63;
46+
import de.tilman_neumann.jml.factor.tdiv.TDiv63Inverse;
4747
import de.tilman_neumann.jml.gcd.Gcd63;
4848
import de.tilman_neumann.jml.primes.probable.BPSWTest;
4949
import de.tilman_neumann.jml.random.SpRand32;
@@ -159,7 +159,7 @@ public ecm_work() {
159159
0, 0, 0, 16, 0, 0, 0, 0, 0, 17,
160160
18, 0 }; // last entry 0 or 1 makes no performance difference
161161

162-
private TDiv63 tdiv = new TDiv63();
162+
private TDiv63Inverse tdiv = new TDiv63Inverse(1<<21);
163163

164164
private BPSWTest bpsw = new BPSWTest();
165165

src/main/java/de/tilman_neumann/jml/factor/ecm/TinyEcm64MH.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
import de.tilman_neumann.jml.factor.FactorAlgorithm;
4444
import de.tilman_neumann.jml.factor.base.FactorArguments;
4545
import de.tilman_neumann.jml.factor.base.FactorResult;
46-
import de.tilman_neumann.jml.factor.tdiv.TDiv63;
46+
import de.tilman_neumann.jml.factor.tdiv.TDiv63Inverse;
4747
import de.tilman_neumann.jml.gcd.Gcd63;
4848
import de.tilman_neumann.jml.primes.probable.BPSWTest;
4949
import de.tilman_neumann.jml.random.SpRand32;
@@ -162,7 +162,7 @@ public ecm_work() {
162162
0, 0, 0, 16, 0, 0, 0, 0, 0, 17,
163163
18, 0 }; // last entry 0 or 1 makes no performance difference
164164

165-
private TDiv63 tdiv = new TDiv63();
165+
private TDiv63Inverse tdiv = new TDiv63Inverse(1<<21);
166166

167167
private BPSWTest bpsw = new BPSWTest();
168168

src/main/java/de/tilman_neumann/jml/factor/ecm/TinyEcm64MHInlined.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
import de.tilman_neumann.jml.factor.FactorAlgorithm;
4444
import de.tilman_neumann.jml.factor.base.FactorArguments;
4545
import de.tilman_neumann.jml.factor.base.FactorResult;
46-
import de.tilman_neumann.jml.factor.tdiv.TDiv63;
46+
import de.tilman_neumann.jml.factor.tdiv.TDiv63Inverse;
4747
import de.tilman_neumann.jml.gcd.Gcd63;
4848
import de.tilman_neumann.jml.primes.probable.BPSWTest;
4949
import de.tilman_neumann.jml.random.SpRand32;
@@ -162,7 +162,7 @@ public ecm_work() {
162162
0, 0, 0, 16, 0, 0, 0, 0, 0, 17,
163163
18, 0 }; // last entry 0 or 1 makes no performance difference
164164

165-
private TDiv63 tdiv = new TDiv63();
165+
private TDiv63Inverse tdiv = new TDiv63Inverse(1<<21);
166166

167167
private BPSWTest bpsw = new BPSWTest();
168168

src/main/java/de/tilman_neumann/jml/factor/tdiv/TDiv.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
* @author Tilman Neumann
3636
*/
3737
public class TDiv extends FactorAlgorithm {
38-
@SuppressWarnings("unused")
38+
3939
private static final Logger LOG = LogManager.getLogger(TDiv.class);
4040
private static final boolean DEBUG = false;
4141

@@ -117,7 +117,6 @@ public void searchFactors(FactorArguments args, FactorResult result) {
117117
// for semiprime N, it would be ~40% faster to do it only after successful divisions
118118
int pbits = 32-Integer.numberOfLeadingZeros(p_i);
119119
if (pbits<<1 >= N.bitLength()) {
120-
// Check if we are done
121120
long p_i_square = ((long)p_i) * p_i;
122121
if (p_i_square > N.longValue()) {
123122
if (DEBUG) LOG.debug("N=" + N + " < p^2 = " + p_i_square);

src/main/java/de/tilman_neumann/jml/factor/tdiv/TDiv63.java

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public void factor(BigInteger Nbig, SortedMultiset<BigInteger> primeFactors) {
6060
int exp = 0;
6161
do {
6262
exp++;
63-
N = N/p;
63+
N /= p;
6464
} while (N%p == 0);
6565
primeFactors.add(BigInteger.valueOf(p), exp);
6666
}
@@ -111,18 +111,19 @@ public void searchFactors(FactorArguments args, FactorResult result) {
111111
if (exp > 0) {
112112
// At least one division has occurred, add the factor(s) to the result map
113113
addToMap(BigInteger.valueOf(p_i), exp*Nexp, primeFactors);
114-
// Check if we are done
115-
if (((long)p_i) * p_i > N) { // move p as long into registers makes a performance difference
116-
// the remaining N is 1 or prime
117-
if (N>1) addToMap(BigInteger.valueOf(N), Nexp, primeFactors);
118-
result.smallestPossibleFactor = p_i; // may be helpful in following factor algorithms
119-
return;
120-
}
114+
}
115+
// for random composite N, it is much much faster to check the termination condition after each p;
116+
// for semiprime N, it would be ~40% faster to do it only after successful divisions
117+
if (((long)p_i) * p_i > N) { // move p as long into registers makes a performance difference
118+
// the remaining N is 1 or prime
119+
if (N>1) addToMap(BigInteger.valueOf(N), Nexp, primeFactors);
120+
result.smallestPossibleFactor = p_i; // may be helpful in following factor algorithms
121+
return;
121122
}
122123
}
123124

124125
result.smallestPossibleFactor = p_i; // may be helpful in following factor algorithms
125-
result.untestedFactors.add(BigInteger.valueOf(N), Nexp); // we do not know if the remaining N is prime or composite
126+
if (N>1) result.untestedFactors.add(BigInteger.valueOf(N), Nexp); // we do not know if the remaining N is prime or composite
126127
}
127128

128129
private void addToMap(BigInteger N, int exp, SortedMap<BigInteger, Integer> map) {

src/main/java/de/tilman_neumann/jml/factor/tdiv/TDiv63Inverse.java

Lines changed: 54 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@
4545
*/
4646
public class TDiv63Inverse extends FactorAlgorithm {
4747
private static final Logger LOG = LogManager.getLogger(TDiv63Inverse.class);
48-
48+
private static final boolean DEBUG = false;
49+
4950
private static AutoExpandingPrimesArray SMALL_PRIMES = AutoExpandingPrimesArray.get();
5051

5152
private static final int DISCRIMINATOR_BITS = 10; // experimental result
@@ -100,11 +101,12 @@ public void factor(BigInteger Nbig, SortedMultiset<BigInteger> primeFactors) {
100101

101102
long N = Nbig.longValue();
102103

103-
int i=0;
104+
int p;
105+
int i = 0;
104106
int pMinBits = NBits - 53 + DISCRIMINATOR_BITS;
105107
if (pMinBits>0) {
106108
// for the smallest primes we must do standard trial division
107-
int pMin = 1<<pMinBits, p;
109+
int pMin = Math.min(1<<pMinBits, pLimit);
108110
for (; (p=primes[i])<pMin; i++) {
109111
int exp = 0;
110112
while (N%p == 0) {
@@ -117,9 +119,8 @@ public void factor(BigInteger Nbig, SortedMultiset<BigInteger> primeFactors) {
117119
}
118120
}
119121

120-
int p, exp;
121122
for (; (p=primes[i])<=pLimit; i++) {
122-
exp = 0;
123+
int exp = 0;
123124
double r = reciprocals[i];
124125
while ((long) (N*r + DISCRIMINATOR) * p == N) {
125126
exp++;
@@ -147,7 +148,6 @@ public void factor(BigInteger Nbig, SortedMultiset<BigInteger> primeFactors) {
147148
* @param args
148149
* @param result a pre-initialized data structure to add results to
149150
*/
150-
// TODO this is a copy from TDiv63. Optimize it for this class.
151151
@Override
152152
public void searchFactors(FactorArguments args, FactorResult result) {
153153
if (args.NBits > 63) throw new IllegalArgumentException(getName() + ".searchFactors() does not work for N>63 bit, but N=" + args.N + " has " + args.NBits + " bit");
@@ -166,29 +166,64 @@ public void searchFactors(FactorArguments args, FactorResult result) {
166166
if (N == 1) return;
167167

168168
SMALL_PRIMES.ensureLimit(pLimit);
169-
169+
170+
if (DEBUG) LOG.debug("N=" + N + ", pLimit = " + pLimit);
171+
170172
int p_i;
171-
for (int i=1; (p_i=SMALL_PRIMES.getPrime(i))<=pLimit; i++) {
172-
int exp = 0;
173-
while (N%p_i == 0) {
174-
N /= p_i;
175-
exp++;
173+
int i = 1;
174+
int Nbits = 64-Long.numberOfLeadingZeros(N);
175+
int pMinBits = Nbits - 53 + DISCRIMINATOR_BITS;
176+
try {
177+
if (pMinBits>0) {
178+
// for the smallest primes we must do standard trial division
179+
int pMin = Math.min(1<<pMinBits, pLimit);
180+
for ( ; (p_i = primes[i]) < pMin; i++) {
181+
int exp = 0;
182+
while (N%p_i == 0) {
183+
N /= p_i;
184+
exp++;
185+
}
186+
if (exp > 0) {
187+
// At least one division has occurred, add the factor(s) to the result map
188+
addToMap(BigInteger.valueOf(p_i), exp*Nexp, primeFactors);
189+
}
190+
}
176191
}
177-
if (exp > 0) {
178-
// At least one division has occurred, add the factor(s) to the result map
179-
addToMap(BigInteger.valueOf(p_i), exp*Nexp, primeFactors);
180-
// Check if we are done
192+
193+
if (N == 1) return;
194+
195+
// Now the primes are big enough to apply trial division by inverses.
196+
// We stop when pLimit is reached, which may have been set before via setTestLimit().
197+
for (; (p_i = primes[i]) <= pLimit; i++) {
198+
if (DEBUG) LOG.trace("N=" + N + ": Test p=" + primes[i]);
199+
int exp = 0;
200+
while (((long) (N*reciprocals[i] + DISCRIMINATOR)) * primes[i] == N) {
201+
N /= p_i;
202+
exp++;
203+
}
204+
if (exp > 0) {
205+
// At least one division has occurred, add the factor(s) to the result map
206+
addToMap(BigInteger.valueOf(p_i), exp*Nexp, primeFactors);
207+
}
208+
// for random composite N, it is much much faster to check the termination condition after each p;
209+
// for semiprime N, it would be ~40% faster to do it only after successful divisions
181210
if (((long)p_i) * p_i > N) { // move p as long into registers makes a performance difference
182211
// the remaining N is 1 or prime
183212
if (N>1) addToMap(BigInteger.valueOf(N), Nexp, primeFactors);
184213
result.smallestPossibleFactor = p_i; // may be helpful in following factor algorithms
185214
return;
186215
}
187216
}
217+
218+
result.smallestPossibleFactor = p_i; // may be helpful in following factor algorithms
219+
if (N>1) result.untestedFactors.add(BigInteger.valueOf(N), Nexp); // we do not know if the remaining N is prime or composite
220+
if (DEBUG) LOG.debug("result = " + result);
221+
222+
} catch (ArrayIndexOutOfBoundsException e) {
223+
int pMaxIndex = primeCountBound-1;
224+
int pMax = primes[pMaxIndex];
225+
LOG.error("TDiv63Inverse has been set up to find factors until p[" + pMaxIndex + "] = " + pMax + ", but now you are trying to access p[" + i + "] !");
188226
}
189-
190-
result.smallestPossibleFactor = p_i; // may be helpful in following factor algorithms
191-
result.untestedFactors.add(BigInteger.valueOf(N), Nexp); // we do not know if the remaining N is prime or composite
192227
}
193228

194229
private void addToMap(BigInteger N, int exp, SortedMap<BigInteger, Integer> map) {

src/test/java/de/tilman_neumann/jml/factor/FactorizerTest.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ public FactorizerTest() {
108108
// new TDiv31(),
109109
new TDiv31Inverse(),
110110
new TDiv31Barrett(), // Fastest algorithm for N < 29 bit
111+
// new TDiv63(),
111112
new TDiv63Inverse(1<<21),
112113
// new TDiv().setTestLimit(1<<20),
113114

0 commit comments

Comments
 (0)