Skip to content

Commit 3ec0da8

Browse files
committed
adjust the required amount of trial division in searchFactors()
1 parent 2d77b54 commit 3ec0da8

File tree

3 files changed

+44
-32
lines changed

3 files changed

+44
-32
lines changed

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

Lines changed: 16 additions & 12 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.TDiv;
46+
import de.tilman_neumann.jml.factor.tdiv.TDiv63;
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;
@@ -53,6 +53,10 @@
5353
* A port of Ben Buhrow's tinyecm.c (https://www.mersenneforum.org/showpost.php?p=521028&postcount=84),
5454
* an ECM implementation for unsigned 64 bit integers.
5555
*
56+
* TinyEcm does not work stable (i.e. it would eventually not terminate) for factor arguments having 2 or more factors < 2^9.
57+
* This issue has been addressed in the searchFactors() method, but not in findSingleFactor(), which should only be used to find factors of semiprimes
58+
* with not too small factors.
59+
*
5660
* @author Tilman Neumann
5761
*/
5862
public class TinyEcm64 extends FactorAlgorithm {
@@ -99,7 +103,7 @@ public ecm_work() {
99103

100104
private static final boolean DEBUG = false;
101105

102-
private static final int MAX_BITS_SUPPORTED = 62;
106+
private static final int MAX_BITS_SUPPORTED = 62; // seems to work for 63 bit numbers now, but very slow - so not completely fixed for that
103107

104108
// The reducer R is 2^64, but the only constant still required is the half of it.
105109
private static final long R_HALF = 1L << 63;
@@ -158,14 +162,14 @@ public ecm_work() {
158162

159163
private long LCGSTATE;
160164

161-
private TDiv tdiv = new TDiv();
165+
private TDiv63 tdiv = new TDiv63();
162166

163167
private BPSWTest bpsw = new BPSWTest();
164168

165169
private Gcd63 gcd63 = new Gcd63();
166170

167171
private SpRand32 spRand32 = new SpRand32();
168-
172+
169173
public String getName() {
170174
return "TinyEcm64";
171175
}
@@ -1086,17 +1090,16 @@ public static long montMul64(long a, long b, long N, long Nhat) {
10861090
* @return factor or 0 if no factor
10871091
*/
10881092
long check_factor(long Z, long n) {
1089-
long f = gcd63.gcd(Z, n);
1093+
long f = gcd63.gcd(Z, n);
10901094
if (DEBUG) LOG.debug("check_factor: gcd(" + Z + ", " + n + ") = " + f);
10911095
return (f>1 && f<n) ? f : 0;
10921096
}
10931097

10941098
/**
1095-
* {@inheritDoc}
1099+
* {@inheritDoc}<br/><br/>
10961100
*
1097-
* <br><br>
1098-
* WARNING: tinyEcm's findSingleFactor() implementation is unstable when called with N having only small factors, like 735=3*5*7^2.
1099-
* In such cases, an suitable amount of trial division should be carried out before.
1101+
* <strong>WARNING: This implementation does not work stable (i.e. it would eventually not terminate) for factor arguments having 2 or more factors < 2^9.</strong>
1102+
* It should only be used when it is clear that this is not the case or after carrying out the required amount of trial division.
11001103
*/
11011104
@Override
11021105
public BigInteger findSingleFactor(BigInteger N) {
@@ -1142,9 +1145,10 @@ public BigInteger findSingleFactor(BigInteger N) {
11421145

11431146
@Override
11441147
public void searchFactors(FactorArguments args, FactorResult result) {
1145-
// tinyEcm is unstable when it comes to find factors of small composites like 735 = 3*5*7^2
1146-
// so we need some trial division first
1147-
tdiv.setTestLimit(1<<16).searchFactors(args, result);
1148+
// tinyEcm fails (i.e. runs forever) for some N having >=2 small factors, like 735 = 3*5*7^2.
1149+
// THe required amount of trial division to fix that has been derived experimentally.
1150+
// With a tdiv limit of 2^8 it still fails sometimes; 2^9 is stable; 2^10 is best in terms of performance.
1151+
tdiv.setTestLimit(1<<10).searchFactors(args, result);
11481152
if (DEBUG) LOG.debug("result after tdiv = " + result);
11491153

11501154
if (result.untestedFactors.isEmpty()) return; // N was "easy"

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

Lines changed: 14 additions & 10 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.TDiv;
46+
import de.tilman_neumann.jml.factor.tdiv.TDiv63;
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;
@@ -56,6 +56,10 @@
5656
* In contrast to TinyEcm64, this variant implements montMul64() using _signed_ multiplications of two 64-bit numbers and Math.multiplyHigh() via Uint128.mul64SignedMH().
5757
* Intrinsics support for Math.multiplyHigh() typically requires Java 10 and not too old hardware.
5858
*
59+
* TinyEcm does not work stable (i.e. it would eventually not terminate) for factor arguments having 2 or more factors < 2^9.
60+
* This issue has been addressed in the searchFactors() method, but not in findSingleFactor(), which should only be used to find factors of semiprimes
61+
* with not too small factors.
62+
*
5963
* @author Tilman Neumann
6064
*/
6165
public class TinyEcm64MH extends FactorAlgorithm {
@@ -161,14 +165,14 @@ public ecm_work() {
161165

162166
private long LCGSTATE;
163167

164-
private TDiv tdiv = new TDiv();
168+
private TDiv63 tdiv = new TDiv63();
165169

166170
private BPSWTest bpsw = new BPSWTest();
167171

168172
private Gcd63 gcd63 = new Gcd63();
169173

170174
private SpRand32 spRand32 = new SpRand32();
171-
175+
172176
public String getName() {
173177
return "TinyEcm64MH";
174178
}
@@ -1096,11 +1100,10 @@ long check_factor(long Z, long n) {
10961100
}
10971101

10981102
/**
1099-
* {@inheritDoc}
1103+
* {@inheritDoc}<br/><br/>
11001104
*
1101-
* <br><br>
1102-
* WARNING: tinyEcm's findSingleFactor() implementation is unstable when called with N having only small factors, like 735=3*5*7^2.
1103-
* In such cases, an suitable amount of trial division should be carried out before.
1105+
* <strong>WARNING: This implementation does not work stable (i.e. it would eventually not terminate) for factor arguments having 2 or more factors < 2^9.</strong>
1106+
* It should only be used when it is clear that this is not the case or after carrying out the required amount of trial division.
11041107
*/
11051108
@Override
11061109
public BigInteger findSingleFactor(BigInteger N) {
@@ -1146,9 +1149,10 @@ public BigInteger findSingleFactor(BigInteger N) {
11461149

11471150
@Override
11481151
public void searchFactors(FactorArguments args, FactorResult result) {
1149-
// tinyEcm is unstable when it comes to find factors of small composites like 735 = 3*5*7^2
1150-
// so we need some trial division first
1151-
tdiv.setTestLimit(1<<16).searchFactors(args, result);
1152+
// tinyEcm fails (i.e. runs forever) for some N having >=2 small factors, like 735 = 3*5*7^2.
1153+
// THe required amount of trial division to fix that has been derived experimentally.
1154+
// With a tdiv limit of 2^8 it still fails sometimes; 2^9 is stable; 2^10 is best in terms of performance.
1155+
tdiv.setTestLimit(1<<10).searchFactors(args, result);
11521156
if (DEBUG) LOG.debug("result after tdiv = " + result);
11531157

11541158
if (result.untestedFactors.isEmpty()) return; // N was "easy"

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

Lines changed: 14 additions & 10 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.TDiv;
46+
import de.tilman_neumann.jml.factor.tdiv.TDiv63;
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;
@@ -56,6 +56,10 @@
5656
* This variant implements montMul64() using _signed_ multiplications of two 64-bit numbers and Math.multiplyHigh().
5757
* Intrinsics support for Math.multiplyHigh() typically requires Java 10 and not too old hardware.
5858
*
59+
* TinyEcm does not work stable (i.e. it would eventually not terminate) for factor arguments having 2 or more factors < 2^9.
60+
* This issue has been addressed in the searchFactors() method, but not in findSingleFactor(), which should only be used to find factors of semiprimes
61+
* with not too small factors.
62+
*
5963
* @author Tilman Neumann
6064
*/
6165
public class TinyEcm64MHInlined extends FactorAlgorithm {
@@ -102,7 +106,7 @@ public ecm_work() {
102106

103107
private static final boolean DEBUG = false;
104108

105-
private static final int MAX_BITS_SUPPORTED = 62;
109+
private static final int MAX_BITS_SUPPORTED = 62; // seems to work for 63 bit numbers now, but very slow - so not completely fixed for that
106110

107111
// The reducer R is 2^64, but the only constant still required is the half of it.
108112
private static final long R_HALF = 1L << 63;
@@ -161,7 +165,7 @@ public ecm_work() {
161165

162166
private long LCGSTATE;
163167

164-
private TDiv tdiv = new TDiv();
168+
private TDiv63 tdiv = new TDiv63();
165169

166170
private BPSWTest bpsw = new BPSWTest();
167171

@@ -1105,11 +1109,10 @@ long check_factor(long Z, long n) {
11051109
}
11061110

11071111
/**
1108-
* {@inheritDoc}
1112+
* {@inheritDoc}<br/><br/>
11091113
*
1110-
* <br><br>
1111-
* WARNING: tinyEcm's findSingleFactor() implementation is unstable when called with N having only small factors, like 735=3*5*7^2.
1112-
* In such cases, an suitable amount of trial division should be carried out before.
1114+
* <strong>WARNING: This implementation does not work stable (i.e. it would eventually not terminate) for factor arguments having 2 or more factors < 2^9.</strong>
1115+
* It should only be used when it is clear that this is not the case or after carrying out the required amount of trial division.
11131116
*/
11141117
@Override
11151118
public BigInteger findSingleFactor(BigInteger N) {
@@ -1155,9 +1158,10 @@ public BigInteger findSingleFactor(BigInteger N) {
11551158

11561159
@Override
11571160
public void searchFactors(FactorArguments args, FactorResult result) {
1158-
// tinyEcm is unstable when it comes to find factors of small composites like 735 = 3*5*7^2
1159-
// so we need some trial division first
1160-
tdiv.setTestLimit(1<<16).searchFactors(args, result);
1161+
// tinyEcm fails (i.e. runs forever) for some N having >=2 small factors, like 735 = 3*5*7^2.
1162+
// THe required amount of trial division to fix that has been derived experimentally.
1163+
// With a tdiv limit of 2^8 it still fails sometimes; 2^9 is stable; 2^10 is best in terms of performance.
1164+
tdiv.setTestLimit(1<<10).searchFactors(args, result);
11611165
if (DEBUG) LOG.debug("result after tdiv = " + result);
11621166

11631167
if (result.untestedFactors.isEmpty()) return; // N was "easy"

0 commit comments

Comments
 (0)