Skip to content

Commit 5a5ec3d

Browse files
committed
more binary search tests, return to old version in sieve classes
1 parent e88b40a commit 5a5ec3d

File tree

4 files changed

+78
-34
lines changed

4 files changed

+78
-34
lines changed

src/main/java/de/tilman_neumann/jml/BinarySearch.java

+23-31
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public class BinarySearch {
2727
/**
2828
* Find the insert position for x into array given that array is sorted bottom-up.
2929
*
30-
* More precisely:
30+
* This version defines the insert position unambiguously, no matter if some entries in the array occur multiple times, as
3131
* If array[maxIndex-1] > x, return the index of the first entry of array[0].. array[maxIndex-1] greater than x.
3232
* If array[maxIndex-1] <= x, return maxIndex.
3333
*
@@ -36,7 +36,7 @@ public class BinarySearch {
3636
* @param x
3737
* @return the insert position
3838
*/
39-
public int getInsertPosition_v1(int[] array, int maxIndex, int x) {
39+
public int getPreciseInsertPosition(int[] array, int maxIndex, int x) {
4040
if (maxIndex<=0 || array[maxIndex-1] <= x) return maxIndex;
4141
int left = 0;
4242
int right = maxIndex-1;
@@ -57,31 +57,11 @@ public int getInsertPosition_v1(int[] array, int maxIndex, int x) {
5757
}
5858
return left;
5959
}
60-
61-
/**
62-
* Find the insert position for x into array given that array is sorted bottom-up.
63-
*
64-
* More precisely:
65-
* If array[maxIndex-1] > x, return the index of the first entry of array[0].. array[maxIndex-1] greater than x.
66-
* If array[maxIndex-1] <= x, return maxIndex.
67-
*
68-
* Faster version using Arrays.binarySearch().
69-
*
70-
* @param array
71-
* @param maxIndex the maximum index to consider, exclusive (may be smaller than the array size)
72-
* @param x
73-
* @return the insert position
74-
*/
75-
public int getInsertPosition/*_v2*/(int[] array, int maxIndex, int x) {
76-
// see @returns in Arrays.binarySearch() javadoc
77-
int i = Arrays.binarySearch(array, 0, maxIndex, x);
78-
return i >= 0 ? i + 1 : -i - 1;
79-
}
8060

8161
/**
8262
* Find the insert position for x into array given that array is sorted bottom-up.
8363
*
84-
* More precisely:
64+
* This version defines the insert position unambiguously, no matter if some entries in the array occur multiple times, as
8565
* If array[maxIndex-1] > x, return the index of the first entry of array[0].. array[maxIndex-1] greater than x.
8666
* If array[maxIndex-1] <= x, return maxIndex.
8767
*
@@ -90,7 +70,7 @@ public int getInsertPosition_v1(int[] array, int maxIndex, int x) {
9070
* @param x
9171
* @return the insert position
9272
*/
93-
public int getInsertPosition_v1(byte[] array, int maxIndex, byte x) {
73+
public int getPreciseInsertPosition(byte[] array, int maxIndex, byte x) {
9474
if (maxIndex<=0 || array[maxIndex-1] <= x) return maxIndex;
9575
int left = 0;
9676
int right = maxIndex-1;
@@ -111,22 +91,34 @@ public int getInsertPosition_v1(byte[] array, int maxIndex, byte x) {
11191
}
11292
return left;
11393
}
114-
94+
11595
/**
11696
* Find the insert position for x into array given that array is sorted bottom-up.
11797
*
118-
* More precisely:
119-
* If array[maxIndex-1] > x, return the index of the first entry of array[0].. array[maxIndex-1] greater than x.
120-
* If array[maxIndex-1] <= x, return maxIndex.
121-
*
122-
* Faster version using Arrays.binarySearch().
98+
* This version is faster than getPreciseInsertPosition(), but "If the range contains multiple elements with the specified value, there is no guarantee which one will be found."
12399
*
124100
* @param array
125101
* @param maxIndex the maximum index to consider, exclusive (may be smaller than the array size)
126102
* @param x
127103
* @return the insert position
128104
*/
129-
public int getInsertPosition/*_v2*/(byte[] array, int maxIndex, byte x) {
105+
public int getInsertPosition(int[] array, int maxIndex, int x) {
106+
// see @returns in Arrays.binarySearch() javadoc
107+
int i = Arrays.binarySearch(array, 0, maxIndex, x);
108+
return i >= 0 ? i + 1 : -i - 1;
109+
}
110+
111+
/**
112+
* Find the insert position for x into array given that array is sorted bottom-up.
113+
*
114+
* This version is faster than getPreciseInsertPosition(), but "If the range contains multiple elements with the specified value, there is no guarantee which one will be found."
115+
*
116+
* @param array
117+
* @param maxIndex the maximum index to consider, but "If the range contains multiple elements with the specified value, there is no guarantee which one will be found."
118+
* @param x
119+
* @return the insert position
120+
*/
121+
public int getInsertPosition(byte[] array, int maxIndex, byte x) {
130122
// see @returns in Arrays.binarySearch() javadoc
131123
int i = Arrays.binarySearch(array, 0, maxIndex, x);
132124
return i >= 0 ? i + 1 : -i - 1;

src/main/java/de/tilman_neumann/jml/factor/siqs/sieve/Sieve03h.java

+4-1
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,8 @@ public void initializeForAParameter(int d, BigInteger daParam, SolutionArrays so
201201
int logP = logPMax;
202202
int lastBound = filteredBaseSize;
203203
for (int i=logPBoundCount-1; i>0; i--) {
204-
lastBound = logPBounds[i] = binarySearch.getInsertPosition(logPArray, lastBound, (byte) --logP);
204+
// here we want the precise insert position because logPArray contains many elements many times
205+
lastBound = logPBounds[i] = binarySearch.getPreciseInsertPosition(logPArray, lastBound, (byte) --logP);
205206
if (DEBUG) LOG.debug("logPBound[" + i + "] = " + logPBounds[i] + ", logP[" + logPBounds[i] + "] = " + logPArray[logPBounds[i]] + ", logP[" + (logPBounds[i]-1) + "] = " + logPArray[logPBounds[i]-1]);
206207
}
207208
logPBounds[0] = p1Index;
@@ -245,6 +246,7 @@ public SieveResult sieve() {
245246
for (int lpbc=logPBoundCount-1; lpbc>=0; lpbc--, bigLogP--) {
246247
int logPBound = logPBounds[lpbc];
247248
for (; i>=logPBound; i--) {
249+
if (DEBUG) Ensure.ensureEquals(logPArray[i], bigLogP);
248250
// x1 == x2 happens only if p divides k -> for large primes p > k there are always 2 distinct solutions.
249251
// x1, x2 may exceed sieveArraySize, but we allocated the arrays somewhat bigger to save the size checks.
250252
sieveArray[x1Array[i]] += bigLogP;
@@ -322,6 +324,7 @@ public SieveResult sieve() {
322324
for (int lpbc=logPBoundCount-1; lpbc>=0; lpbc--, bigLogP--) {
323325
int logPBound = logPBounds[lpbc];
324326
for (; i>=logPBound; i--) {
327+
if (DEBUG) Ensure.ensureEquals(logPArray[i], bigLogP);
325328
final int p = pArray[i];
326329
sieveArray[p-x1Array[i]] += bigLogP;
327330
sieveArray[p-x2Array[i]] += bigLogP;

src/main/java/de/tilman_neumann/jml/factor/siqs/sieve/Sieve03hU.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import static de.tilman_neumann.jml.factor.base.GlobalFactoringOptions.*;
1818

1919
import java.math.BigInteger;
20+
import java.util.Arrays;
2021

2122
import org.apache.logging.log4j.Logger;
2223
import org.apache.logging.log4j.LogManager;
@@ -202,7 +203,8 @@ public void initializeForAParameter(int d, BigInteger daParam, SolutionArrays so
202203
int logP = logPMax;
203204
int lastBound = filteredBaseSize;
204205
for (int i=logPBoundCount-1; i>0; i--) {
205-
lastBound = logPBounds[i] = binarySearch.getInsertPosition(logPArray, lastBound, (byte) --logP);
206+
// here we want the precise insert position because logPArray contains many elements many times
207+
lastBound = logPBounds[i] = binarySearch.getPreciseInsertPosition(logPArray, lastBound, (byte) --logP);
206208
if (DEBUG) LOG.debug("logPBound[" + i + "] = " + logPBounds[i] + ", logP[" + logPBounds[i] + "] = " + logPArray[logPBounds[i]] + ", logP[" + (logPBounds[i]-1) + "] = " + logPArray[logPBounds[i]-1]);
207209
}
208210
logPBounds[0] = p1Index;
@@ -247,6 +249,7 @@ public SieveResult sieve() {
247249
for (int lpbc=logPBoundCount-1; lpbc>=0; lpbc--, bigLogP--) {
248250
int logPBound = logPBounds[lpbc];
249251
for (; i>=logPBound; i--) {
252+
if (DEBUG) Ensure.ensureEquals(logPArray[i], bigLogP);
250253
// x1 == x2 happens only if p divides k -> for large primes p > k there are always 2 distinct solutions.
251254
// x1, x2 may exceed sieveArraySize, but we allocated the arrays somewhat bigger to save the size checks.
252255
x1Addr = sieveArrayAddress + x1Array[i];
@@ -365,6 +368,7 @@ public SieveResult sieve() {
365368
for (int lpbc=logPBoundCount-1; lpbc>=0; lpbc--, bigLogP--) {
366369
int logPBound = logPBounds[lpbc];
367370
for (; i>=logPBound; i--) {
371+
if (DEBUG) Ensure.ensureEquals(logPArray[i], bigLogP);
368372
final int p = pArray[i];
369373
x1Addr = sieveArrayAddress + p - x1Array[i];
370374
UNSAFE.putByte(x1Addr, (byte) (UNSAFE.getByte(x1Addr) + bigLogP));

src/test/java/de/tilman_neumann/jml/BinarySearchTest.java

+46-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* java-math-library is a Java library focused on number theory, but not necessarily limited to it. It is based on the PSIQS 4.0 factoring project.
3-
* Copyright (C) 2018-2024 Tilman Neumann - tilman.neumann@web.de
3+
* Copyright (C) 2018-2025 Tilman Neumann - tilman.neumann@web.de
44
*
55
* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License
66
* as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
@@ -14,6 +14,7 @@
1414
package de.tilman_neumann.jml;
1515

1616
import static org.junit.Assert.assertEquals;
17+
import static org.junit.Assert.assertNotEquals;
1718

1819
import java.util.Arrays;
1920

@@ -38,6 +39,27 @@ public void setup() {
3839
ConfigUtil.initProject();
3940
}
4041

42+
@Test
43+
public void testGetPreciseInsertPosition() {
44+
int[] array = new int[] {1, 2, 3, 7, 10, 10, 11};
45+
assertCorrectPreciseInsertPosition(array, 4, 3, 3);
46+
assertCorrectPreciseInsertPosition(array, 4, 20, 4); // insert index can not exceed maxIndex
47+
assertCorrectPreciseInsertPosition(array, 7, 10, 6);
48+
assertCorrectPreciseInsertPosition(array, 7, 11, 7);
49+
assertCorrectPreciseInsertPosition(array, 7, 20, 7);
50+
}
51+
52+
@Test
53+
public void testGetPreciseInsertPositionWithMultipleEntries() {
54+
// each entry occurs 10 times
55+
int[] array = new int[] {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7};
56+
assertCorrectPreciseInsertPosition(array, 70, 5, 50);
57+
assertCorrectPreciseInsertPosition(array, 59, 4, 40);
58+
assertCorrectPreciseInsertPosition(array, 55, 3, 30);
59+
assertCorrectPreciseInsertPosition(array, 42, 2, 20);
60+
assertCorrectPreciseInsertPosition(array, 15, 1, 10);
61+
}
62+
4163
@Test
4264
public void testGetInsertPosition() {
4365
int[] array = new int[] {1, 2, 3, 7, 10, 10, 11};
@@ -48,9 +70,32 @@ public void testGetInsertPosition() {
4870
assertCorrectInsertPosition(array, 7, 20, 7);
4971
}
5072

73+
@Test
74+
public void testGetAmbigousInsertPositionWithMultipleEntries() {
75+
// each entry occurs 10 times
76+
int[] array = new int[] {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7};
77+
assertWrongInsertPosition(array, 70, 5, 50);
78+
assertWrongInsertPosition(array, 59, 4, 40);
79+
assertWrongInsertPosition(array, 55, 3, 30);
80+
assertWrongInsertPosition(array, 42, 2, 20);
81+
assertWrongInsertPosition(array, 15, 1, 10);
82+
}
83+
84+
private static void assertCorrectPreciseInsertPosition(int[] array, int maxIndex, int x, int expectedInsertIndex) {
85+
int index = bs.getPreciseInsertPosition(array, maxIndex, x);
86+
LOG.info("precise insert index of '" + x + "' in " + Arrays.toString(array) + " (restricted to maxIndex=" + maxIndex + ") = " + index);
87+
assertEquals(expectedInsertIndex, index);
88+
}
89+
5190
private static void assertCorrectInsertPosition(int[] array, int maxIndex, int x, int expectedInsertIndex) {
5291
int index = bs.getInsertPosition(array, maxIndex, x);
5392
LOG.info("insert index of '" + x + "' in " + Arrays.toString(array) + " (restricted to maxIndex=" + maxIndex + ") = " + index);
5493
assertEquals(expectedInsertIndex, index);
5594
}
95+
96+
private static void assertWrongInsertPosition(int[] array, int maxIndex, int x, int expectedInsertIndex) {
97+
int index = bs.getInsertPosition(array, maxIndex, x);
98+
LOG.info("insert index of '" + x + "' in " + Arrays.toString(array) + " (restricted to maxIndex=" + maxIndex + ") = " + index);
99+
assertNotEquals(expectedInsertIndex, index);
100+
}
56101
}

0 commit comments

Comments
 (0)