You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by lu...@apache.org on 2014/07/21 18:38:45 UTC

svn commit: r1612346 - in /commons/proper/math/trunk/src: main/java/org/apache/commons/math3/stat/descriptive/rank/Percentile.java test/java/org/apache/commons/math3/stat/descriptive/rank/PercentileTest.java

Author: luc
Date: Mon Jul 21 16:38:45 2014
New Revision: 1612346

URL: http://svn.apache.org/r1612346
Log:
Refactored removeAndSlice, replaceAndSlice.

Thansk to Venkatesha Murthy TS for the patch.

JIRA: MATH-1120

Modified:
    commons/proper/math/trunk/src/main/java/org/apache/commons/math3/stat/descriptive/rank/Percentile.java
    commons/proper/math/trunk/src/test/java/org/apache/commons/math3/stat/descriptive/rank/PercentileTest.java

Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/stat/descriptive/rank/Percentile.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/stat/descriptive/rank/Percentile.java?rev=1612346&r1=1612345&r2=1612346&view=diff
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/stat/descriptive/rank/Percentile.java (original)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/stat/descriptive/rank/Percentile.java Mon Jul 21 16:38:45 2014
@@ -17,9 +17,8 @@
 package org.apache.commons.math3.stat.descriptive.rank;
 
 import java.io.Serializable;
-import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.List;
+import java.util.BitSet;
 
 import org.apache.commons.math3.exception.MathIllegalArgumentException;
 import org.apache.commons.math3.exception.MathUnsupportedOperationException;
@@ -34,6 +33,7 @@ import org.apache.commons.math3.util.Mat
 import org.apache.commons.math3.util.MathUtils;
 import org.apache.commons.math3.util.MedianOf3PivotingStrategy;
 import org.apache.commons.math3.util.PivotingStrategyInterface;
+import org.apache.commons.math3.util.Precision;
 
 /**
  * Provides percentile computation.
@@ -492,13 +492,12 @@ public class Percentile extends Abstract
      */
     private static double[] replaceAndSlice(final double[] values,
                                             final int begin, final int length,
-                                            final double original, final double replacement) {
+                                            final double original,
+                                            final double replacement) {
         final double[] temp = copyOf(values, begin, length);
         for(int i = 0; i < length; i++) {
-            //First a quick check on if both are NaN
-            final boolean areBothNaNs = Double.isNaN(original) &&
-                                    Double.isNaN(values[i]);
-            temp[i] = (areBothNaNs || Double.compare(original, temp[i]) == 0) ? replacement : temp[i];
+            temp[i] = Precision.equalsIncludingNaN(original, temp[i]) ?
+                      replacement : temp[i];
         }
         return temp;
     }
@@ -516,38 +515,34 @@ public class Percentile extends Abstract
                                            final int begin, final int length,
                                            final double removedValue) {
         MathArrays.verifyValues(values, begin, length);
-
-        final double [] temp;
-        final List<Integer> occurencesToRemove = new ArrayList<Integer>();
-
-        //First register for all occurrences of removable value
-        for (int i= begin; i < begin + length; i++) {
-            //Do a quick check on if both are NaN
-            final boolean areBothNaNs = Double.isNaN(removedValue) && Double.isNaN(values[i]);
-            if (areBothNaNs || Double.compare(values[i], removedValue) == 0) {
-                occurencesToRemove.add(i);
+        final double[] temp;
+        //BitSet(length) to indicate where the removedValue is located
+        final BitSet bits = new BitSet(length);
+        for (int i = begin; i < begin+length; i++) {
+            if (Precision.equalsIncludingNaN(removedValue, values[i])) {
+                bits.set(i - begin);
             }
         }
-
-        //Next, get the slice of array with removable peeled off.
-        if (occurencesToRemove.isEmpty()) {
-            temp = copyOf(values,begin,length); //just do a copy
-        } else if (occurencesToRemove.size() == length) {
-            temp = new double[0]; //all were NaNs; so return a zero length
-        } else /*if(occurancesToRemove.size()>0)*/ {
-            temp = new double[length - occurencesToRemove.size()];
-            int start = begin;
-            int destStart = 0;
-            // copy off the retained ones in steps
-            for (final int current: occurencesToRemove) {
-                final int numsToMove = current - start;
-                System.arraycopy(values, start, temp, destStart, numsToMove);
-                destStart += numsToMove;
-                start = current + 1;
+        //Check if empty then create a new copy
+        if (bits.isEmpty()) {
+            temp = copyOf(values, begin, length); // Nothing removed, just copy
+        } else if(bits.cardinality() == length){
+            temp = new double[0];                 // All removed, just empty
+        }else {                                   // Some removable, so new
+            temp = new double[length - bits.cardinality()];
+            int start = begin;  //start index from source array (i.e values)
+            int dest = 0;       //dest index in destination array(i.e temp)
+            int nextOne = -1;   //nextOne is the index of bit set of next one
+            int bitSetPtr = 0;  //bitSetPtr is start index pointer of bitset
+            while ((nextOne = bits.nextSetBit(bitSetPtr)) != -1) {
+                final int lengthToCopy = nextOne - bitSetPtr;
+                System.arraycopy(values, start, temp, dest, lengthToCopy);
+                dest += lengthToCopy;
+                start = begin + (bitSetPtr = bits.nextClearBit(nextOne));
             }
-            //Copy any residue past start index till length
-            if (start < length) {
-                System.arraycopy(values,start,temp,destStart,length-start);
+            //Copy any residue past start index till begin+length
+            if (start < begin + length) {
+                System.arraycopy(values,start,temp,dest,begin + length - start);
             }
         }
         return temp;

Modified: commons/proper/math/trunk/src/test/java/org/apache/commons/math3/stat/descriptive/rank/PercentileTest.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/java/org/apache/commons/math3/stat/descriptive/rank/PercentileTest.java?rev=1612346&r1=1612345&r2=1612346&view=diff
==============================================================================
--- commons/proper/math/trunk/src/test/java/org/apache/commons/math3/stat/descriptive/rank/PercentileTest.java (original)
+++ commons/proper/math/trunk/src/test/java/org/apache/commons/math3/stat/descriptive/rank/PercentileTest.java Mon Jul 21 16:38:45 2014
@@ -786,6 +786,18 @@ public class PercentileTest extends Univ
         Assert.assertEquals(2d,new Percentile(50d).withEstimationType(Percentile.EstimationType.R_1).withNaNStrategy(NaNStrategy.REMOVED).evaluate(specialValues),0d);
         Assert.assertEquals(Double.NaN,new Percentile(50d).withEstimationType(Percentile.EstimationType.R_5).withNaNStrategy(NaNStrategy.REMOVED).evaluate(new double[] {Double.NaN,Double.NaN,Double.NaN}),0d);
         Assert.assertEquals(50d,new Percentile(50d).withEstimationType(Percentile.EstimationType.R_7).withNaNStrategy(NaNStrategy.MINIMAL).evaluate(new double[] {50d,50d,50d},1,2),0d);
+        
+        specialValues = new double[] { 0d, 1d, 2d, 3d, 4d, Double.NaN, Double.NaN };
+        Assert.assertEquals(3.5,new Percentile().evaluate(specialValues, 3, 4),0d);
+        Assert.assertEquals(4d,new Percentile().evaluate(specialValues, 4, 3),0d);
+        Assert.assertTrue(Double.isNaN(new Percentile().evaluate(specialValues, 5, 2)));
+        
+        specialValues = new double[] { 0d, 1d, 2d, 3d, 4d, Double.NaN, Double.NaN, 5d, 6d };
+        Assert.assertEquals(4.5,new Percentile().evaluate(specialValues, 3, 6),0d);
+        Assert.assertEquals(5d,new Percentile().evaluate(specialValues, 4, 5),0d);
+        Assert.assertTrue(Double.isNaN(new Percentile().evaluate(specialValues, 5, 2)));
+        Assert.assertTrue(Double.isNaN(new Percentile().evaluate(specialValues, 5, 1)));
+        Assert.assertEquals(5.5,new Percentile().evaluate(specialValues, 5, 4),0d);
     }
 
     // Some NaNStrategy specific testing
@@ -796,7 +808,7 @@ public class PercentileTest extends Univ
         new Percentile(50d).
         withEstimationType(Percentile.EstimationType.R_9).
         withNaNStrategy(NaNStrategy.FAILED).
-        evaluate(specialValues, 3, 3);
+        evaluate(specialValues);
     }
 
     @Test