This is an automated email from the ASF dual-hosted git repository.

asf-gitbox-commits pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-numbers.git


The following commit(s) were added to refs/heads/master by this push:
     new 7d6f68ea NUMBERS-213: Restore signed zeros within the [from, to) range
7d6f68ea is described below

commit 7d6f68ea13253804c0a809f13b83a9ca0b84932c
Author: Alex Herbert <[email protected]>
AuthorDate: Fri Aug 21 09:33:28 2026 +0100

    NUMBERS-213: Restore signed zeros within the [from, to) range
---
 .../apache/commons/numbers/arrays/Selection.java   | 15 ++++++----
 .../commons/numbers/arrays/SelectionTest.java      | 33 ++++++++++++++++++++++
 src/changes/changes.xml                            |  5 ++++
 3 files changed, 48 insertions(+), 5 deletions(-)

diff --git 
a/commons-numbers-arrays/src/main/java/org/apache/commons/numbers/arrays/Selection.java
 
b/commons-numbers-arrays/src/main/java/org/apache/commons/numbers/arrays/Selection.java
index 45636ab0..d54fb888 100644
--- 
a/commons-numbers-arrays/src/main/java/org/apache/commons/numbers/arrays/Selection.java
+++ 
b/commons-numbers-arrays/src/main/java/org/apache/commons/numbers/arrays/Selection.java
@@ -242,8 +242,10 @@ public final class Selection {
 
         // Restore signed zeros
         if (cn != 0) {
-            // Use partition index below zero to fast-forward to zero as much 
as possible
-            for (int j = a[k] < 0 ? k : -1;;) {
+            // Use partition index below zero to fast-forward to zero as much 
as possible.
+            // The scan must start within the range to avoid modifying data
+            // outside [fromIndex, toIndex).
+            for (int j = a[k] < 0 ? k : fromIndex - 1;;) {
                 if (a[++j] == 0) {
                     a[j] = -0.0;
                     if (--cn == 0) {
@@ -311,8 +313,10 @@ public final class Selection {
 
         // Restore signed zeros
         if (cn != 0) {
-            // Use partition indices below zero to fast-forward to zero as 
much as possible
-            int j = -1;
+            // Use partition indices below zero to fast-forward to zero as 
much as possible.
+            // The scan must start within the range to avoid modifying data
+            // outside [fromIndex, toIndex).
+            int j = fromIndex - 1;
             if (n < 0) {
                 // Binary search on -n sorted indices: hi = (-n) - 1
                 int lo = 0;
@@ -320,7 +324,8 @@ public final class Selection {
                 while (lo <= hi) {
                     final int mid = (lo + hi) >>> 1;
                     if (a[k[mid]] < 0) {
-                        j = mid;
+                        // Track the index into the data, not the index into k
+                        j = k[mid];
                         lo = mid + 1;
                     } else {
                         hi = mid - 1;
diff --git 
a/commons-numbers-arrays/src/test/java/org/apache/commons/numbers/arrays/SelectionTest.java
 
b/commons-numbers-arrays/src/test/java/org/apache/commons/numbers/arrays/SelectionTest.java
index b4801b6f..f1524816 100644
--- 
a/commons-numbers-arrays/src/test/java/org/apache/commons/numbers/arrays/SelectionTest.java
+++ 
b/commons-numbers-arrays/src/test/java/org/apache/commons/numbers/arrays/SelectionTest.java
@@ -562,6 +562,39 @@ class SelectionTest {
         }, false);
     }
 
+    /**
+     * Test that selection on a sub-range does not modify data outside the 
range
+     * {@code [fromIndex, toIndex)} when restoring signed zeros, and restores 
the
+     * negative zeros inside the range.
+     */
+    @Test
+    void testDoubleSelectRangeSignedZerosOutsideRangeUntouched() {
+        // A zero below the range must not be rewritten by the restoration scan
+        // when the range contains no negative values to fast-forward from.
+        final double[] a = {0.0, 0.0, -0.0};
+        Selection.select(a, 1, 3, 2);
+        Assertions.assertArrayEquals(new double[] {0.0, -0.0, 0.0}, a, "single 
k");
+        final double[] b = {0.0, 0.0, -0.0};
+        Selection.select(b, 1, 3, new int[] {1, 2});
+        Assertions.assertArrayEquals(new double[] {0.0, -0.0, 0.0}, b, 
"multiple k");
+    }
+
+    /**
+     * Test that selection on a sub-range does not modify data outside the 
range
+     * {@code [fromIndex, toIndex)} when restoring signed zeros using the
+     * fast-forward from sorted partition indices with values below zero.
+     */
+    @Test
+    void testDoubleSelectRangeSignedZerosFastForwardWithinRange() {
+        // Negative values inside the range: the fast-forward must use the
+        // partition index into the data, not the index into k, otherwise the
+        // restoration scan may start below fromIndex.
+        final double[] a = {0.0, 0.0, 0.0, 0.0, 7.0, -1.0, -0.0, 8.0, -3.0, 
-2.0};
+        Selection.select(a, 4, 10, new int[] {4, 5, 6, 7, 8, 9});
+        Assertions.assertArrayEquals(
+            new double[] {0.0, 0.0, 0.0, 0.0, -3.0, -2.0, -1.0, -0.0, 7.0, 
8.0}, a);
+    }
+
     static void assertPartition(double[] values, int[] indices, 
DoublePartitionFunction function,
         boolean sortedRange) {
         final double[] data = values.clone();
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 2cf87881..b4da3c11 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -56,6 +56,11 @@ If the output is not quite correct, check for invisible 
trailing spaces!
     <release version="1.4" date="TBD" description="
 New features, updates and bug fixes.
 ">
+      <action dev="aherbert" type="fix" due-to="Security scan, Alex Herbert" 
issue="NUMBERS-213">
+        "Selection": Fix silent modification of the sign of zeros outside the
+        [fromIndex, toIndex) range due to incorrectly restoring signs from the 
start
+        of the array.
+      </action>
       <action dev="aherbert" type="fix" due-to="Security scan, Alex Herbert" 
issue="NUMBERS-212">
         "MultidimensionalCounter": Any product of strictly positive dimension 
sizes
         equal or above 2^31 is rejected.

Reply via email to