]> source.dussan.org Git - poi.git/commitdiff
replace over engineered inner classes with lambdas/method references
authorAndreas Beeker <kiwiwings@apache.org>
Tue, 13 Apr 2021 19:44:38 +0000 (19:44 +0000)
committerAndreas Beeker <kiwiwings@apache.org>
Tue, 13 Apr 2021 19:44:38 +0000 (19:44 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1888743 13f79535-47bb-0310-9956-ffa450edef68

16 files changed:
poi/src/main/java/org/apache/poi/ss/formula/eval/FunctionEval.java
poi/src/main/java/org/apache/poi/ss/formula/functions/ArrayFunction.java
poi/src/main/java/org/apache/poi/ss/formula/functions/BooleanFunction.java
poi/src/main/java/org/apache/poi/ss/formula/functions/Column.java
poi/src/main/java/org/apache/poi/ss/formula/functions/Even.java [deleted file]
poi/src/main/java/org/apache/poi/ss/formula/functions/Fixed0ArgFunction.java
poi/src/main/java/org/apache/poi/ss/formula/functions/Log.java [new file with mode: 0644]
poi/src/main/java/org/apache/poi/ss/formula/functions/MathX.java
poi/src/main/java/org/apache/poi/ss/formula/functions/Na.java
poi/src/main/java/org/apache/poi/ss/formula/functions/Now.java
poi/src/main/java/org/apache/poi/ss/formula/functions/NumericFunction.java
poi/src/main/java/org/apache/poi/ss/formula/functions/Odd.java [deleted file]
poi/src/main/java/org/apache/poi/ss/formula/functions/Poisson.java [new file with mode: 0644]
poi/src/main/java/org/apache/poi/ss/formula/functions/RowFunc.java
poi/src/main/java/org/apache/poi/ss/formula/functions/Today.java
poi/src/test/java/org/apache/poi/ss/formula/functions/TestRowCol.java

index da670439a9d9356c101561a1051f200cf869aa5f..b5fdb8a8c8cab1406c40485b611b1f9e8917ecf6 100644 (file)
@@ -73,9 +73,9 @@ public final class FunctionEval {
         retval[5] = AggregateFunction.AVERAGE;
         retval[6] = AggregateFunction.MIN;
         retval[7] = AggregateFunction.MAX;
-        retval[8] = new RowFunc(); // ROW
-        retval[9] = new Column();
-        retval[10] = new Na();
+        retval[8] = RowFunc::evaluate; // ROW
+        retval[9] = Column::evaluate;
+        retval[10] = Na::evaluate;
         retval[11] = new Npv();
         retval[12] = AggregateFunction.STDEV;
         retval[13] = NumericFunction.DOLLAR;
@@ -137,7 +137,7 @@ public final class FunctionEval {
         retval[71] = CalendarFieldFunction.HOUR;
         retval[72] = CalendarFieldFunction.MINUTE;
         retval[73] = CalendarFieldFunction.SECOND;
-        retval[74] = new Now();
+        retval[74] = Now::evaluate;
         retval[75] = new Areas();
         retval[76] = new Rows();
         retval[77] = new Columns();
@@ -226,7 +226,7 @@ public final class FunctionEval {
         retval[216] = new Rank();
         retval[219] = new Address();
         retval[220] = new Days360();
-        retval[221] = new Today();
+        retval[221] = Today::evaluate;
         //222: VBD
 
         retval[227] = AggregateFunction.MEDIAN;
@@ -259,7 +259,7 @@ public final class FunctionEval {
         retval[276] = NumericFunction.COMBIN;
         // 277: CONFIDENCE
         // 278:CRITBINOM
-        retval[279] = new Even();
+        retval[279] = NumericFunction.EVEN;
         // 280: EXPONDIST
         // 281: FDIST
         // 282: FINV
@@ -278,7 +278,7 @@ public final class FunctionEval {
         // 295: NORMINV
         // 296: NORMSINV
         // 297: STANDARDIZE
-        retval[298] = new Odd();
+        retval[298] = NumericFunction.ODD;
         // 299: PERMUT
         retval[300] = NumericFunction.POISSON;
         // 301: TDIST
index 0e842fc5c9f0edbf1c391cdd884f96088bcd7ab3..46b89d50133d3566574f97ade2a4724d7e87049b 100644 (file)
@@ -29,13 +29,13 @@ import java.util.function.BiFunction;
  */
 
 public interface ArrayFunction {
-    
+
     /**
      * @param args the evaluated function arguments.  Empty values are represented with
-     * {@link BlankEval} or {@link MissingArgEval}, never <code>null</code>.
+     * {@link BlankEval} or {@link MissingArgEval}, never {@code null}.
      * @param srcRowIndex row index of the cell containing the formula under evaluation
      * @param srcColumnIndex column index of the cell containing the formula under evaluation
-     * @return The evaluated result, possibly an {@link ErrorEval}, never <code>null</code>.
+     * @return The evaluated result, possibly an {@link ErrorEval}, never {@code null}.
      * <b>Note</b> - Excel uses the error code <i>#NUM!</i> instead of IEEE <i>NaN</i>, so when
      * numeric functions evaluate to {@link Double#NaN} be sure to translate the result to {@link
      * ErrorEval#NUM_ERROR}.
@@ -47,19 +47,29 @@ public interface ArrayFunction {
      * Evaluate an array function with two arguments.
      *
      * @param arg0 the first function argument. Empty values are represented with
-     *        {@link BlankEval} or {@link MissingArgEval}, never <code>null</code>
+     *        {@link BlankEval} or {@link MissingArgEval}, never {@code null}
      * @param arg1 the first function argument. Empty values are represented with
-     *      @link BlankEval} or {@link MissingArgEval}, never <code>null</code>
+     *      @link BlankEval} or {@link MissingArgEval}, never {@code null}
      *
      * @param srcRowIndex row index of the cell containing the formula under evaluation
      * @param srcColumnIndex column index of the cell containing the formula under evaluation
-     * @return The evaluated result, possibly an {@link ErrorEval}, never <code>null</code>.
+     * @return The evaluated result, possibly an {@link ErrorEval}, never {@code null}.
      * <b>Note</b> - Excel uses the error code <i>#NUM!</i> instead of IEEE <i>NaN</i>, so when
      * numeric functions evaluate to {@link Double#NaN} be sure to translate the result to {@link
      * ErrorEval#NUM_ERROR}.
      */
     default ValueEval evaluateTwoArrayArgs(ValueEval arg0, ValueEval arg1, int srcRowIndex, int srcColumnIndex,
                                            BiFunction<ValueEval, ValueEval, ValueEval> evalFunc) {
+        return _evaluateTwoArrayArgs(arg0, arg1, srcRowIndex, srcColumnIndex, evalFunc);
+    }
+
+    default ValueEval evaluateOneArrayArg(ValueEval arg0, int srcRowIndex, int srcColumnIndex,
+                                          java.util.function.Function<ValueEval, ValueEval> evalFunc) {
+        return _evaluateOneArrayArg(arg0, srcRowIndex, srcColumnIndex, evalFunc);
+    }
+
+    static ValueEval _evaluateTwoArrayArgs(ValueEval arg0, ValueEval arg1, int srcRowIndex, int srcColumnIndex,
+        BiFunction<ValueEval, ValueEval, ValueEval> evalFunc) {
         int w1, w2, h1, h2;
         int a1FirstCol = 0, a1FirstRow = 0;
         if (arg0 instanceof AreaEval) {
@@ -150,8 +160,9 @@ public interface ArrayFunction {
         return new CacheAreaEval(srcRowIndex, srcColumnIndex, srcRowIndex + height - 1, srcColumnIndex + width - 1, vals);
     }
 
-    default ValueEval evaluateOneArrayArg(ValueEval arg0, int srcRowIndex, int srcColumnIndex,
-                                          java.util.function.Function<ValueEval, ValueEval> evalFunc){
+
+    static ValueEval _evaluateOneArrayArg(ValueEval arg0, int srcRowIndex, int srcColumnIndex,
+        java.util.function.Function<ValueEval, ValueEval> evalFunc){
         int w1, w2, h1, h2;
         int a1FirstCol = 0, a1FirstRow = 0;
         if (arg0 instanceof AreaEval) {
@@ -204,7 +215,6 @@ public interface ArrayFunction {
         }
 
         return new CacheAreaEval(srcRowIndex, srcColumnIndex, srcRowIndex + height - 1, srcColumnIndex + width - 1, vals);
-
     }
 
 }
index 5177b851a6471daf3c191bef11cc27c1105b127a..885609ae414fef28b4fbfec80ea2737fdda97276 100644 (file)
@@ -34,8 +34,6 @@ import org.apache.poi.ss.formula.eval.ValueEval;
  * <li> Numbers: 0 is false. Any other number is TRUE </li>
  * <li> Areas: *all* cells in area are evaluated according to the above rules</li>
  * </ol>
- *
- * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
  */
 public abstract class BooleanFunction implements Function,ArrayFunction {
 
@@ -132,43 +130,12 @@ public abstract class BooleanFunction implements Function,ArrayFunction {
                        return cumulativeResult || currentValue;
                }
        };
-       public static final Function FALSE = new Fixed0ArgFunction() {
-               public ValueEval evaluate(int srcRowIndex, int srcColumnIndex) {
-                       return BoolEval.FALSE;
-               }
-       };
-       public static final Function TRUE = new Fixed0ArgFunction() {
-               public ValueEval evaluate(int srcRowIndex, int srcColumnIndex) {
-                       return BoolEval.TRUE;
-               }
-       };
 
-       abstract static class Boolean1ArgFunction extends Fixed1ArgFunction implements ArrayFunction {
-               @Override
-               public ValueEval evaluateArray(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
-                       if (args.length != 1) {
-                               return ErrorEval.VALUE_INVALID;
-                       }
-                       return evaluateOneArrayArg(args[0], srcRowIndex, srcColumnIndex,
-                                       vA -> evaluate(srcRowIndex, srcColumnIndex, vA));
-               }
+       public static final Function FALSE = BooleanFunction::evaluateFalse;
 
-       }
+       public static final Function TRUE = BooleanFunction::evaluateTrue;
 
-       public static final Function NOT = new Boolean1ArgFunction() {
-               public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) {
-                       boolean boolArgVal;
-                       try {
-                               ValueEval ve = OperandResolver.getSingleValue(arg0, srcRowIndex, srcColumnIndex);
-                               Boolean b = OperandResolver.coerceValueToBoolean(ve, false);
-                               boolArgVal = b == null ? false : b;
-                       } catch (EvaluationException e) {
-                               return e.getErrorEval();
-                       }
-
-                       return BoolEval.valueOf(!boolArgVal);
-               }
-       };
+       public static final Function NOT = BooleanFunction::evaluateNot;
 
        @Override
        public ValueEval evaluateArray(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
@@ -178,4 +145,30 @@ public abstract class BooleanFunction implements Function,ArrayFunction {
                return evaluateOneArrayArg(args[0], srcRowIndex, srcColumnIndex,
                                vA -> evaluate(new ValueEval[]{vA}, srcRowIndex, srcColumnIndex));
        }
+
+       private static ValueEval evaluateFalse(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
+               return args.length != 0 ? ErrorEval.VALUE_INVALID : BoolEval.FALSE;
+       }
+
+       private static ValueEval evaluateTrue(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
+               return args.length != 0 ? ErrorEval.VALUE_INVALID : BoolEval.TRUE;
+       }
+
+       private static ValueEval evaluateNot(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
+               if (args.length != 1) {
+                       return ErrorEval.VALUE_INVALID;
+               }
+               java.util.function.Function<ValueEval, ValueEval> notInner = (va) -> {
+                       try {
+                               ValueEval ve = OperandResolver.getSingleValue(va, srcRowIndex, srcColumnIndex);
+                               Boolean b = OperandResolver.coerceValueToBoolean(ve, false);
+                               boolean boolArgVal = b != null && b;
+                               return BoolEval.valueOf(!boolArgVal);
+                       } catch (EvaluationException e) {
+                               return e.getErrorEval();
+                       }
+               };
+
+               return ArrayFunction._evaluateOneArrayArg(args[0], srcRowIndex, srcColumnIndex, notInner);
+       }
 }
\ No newline at end of file
index 9c152bb17ff391b102ae63d16c3cd812d17e316b..6e2c9bcb097c04f8d3fea46698f162ca8ca5577f 100644 (file)
@@ -23,18 +23,19 @@ import org.apache.poi.ss.formula.eval.NumberEval;
 import org.apache.poi.ss.formula.eval.RefEval;
 import org.apache.poi.ss.formula.eval.ValueEval;
 
-public final class Column implements Function0Arg, Function1Arg {
+public final class Column {
+    public static ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
+        if (args.length > 1) {
+            return ErrorEval.VALUE_INVALID;
+        }
 
-    public ValueEval evaluate(int srcRowIndex, int srcColumnIndex) {
-        return new NumberEval(srcColumnIndex+1.);
-    }
-    public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) {
         int rnum;
-
-        if (arg0 instanceof AreaEval) {
-            rnum = ((AreaEval) arg0).getFirstColumn();
-        } else if (arg0 instanceof RefEval) {
-            rnum = ((RefEval) arg0).getColumn();
+        if (args.length == 0) {
+            rnum = srcColumnIndex;
+        } else if (args[0] instanceof AreaEval) {
+            rnum = ((AreaEval) args[0]).getFirstColumn();
+        } else if (args[0] instanceof RefEval) {
+            rnum = ((RefEval) args[0]).getColumn();
         } else {
             // anything else is not valid argument
             return ErrorEval.VALUE_INVALID;
@@ -42,13 +43,4 @@ public final class Column implements Function0Arg, Function1Arg {
 
         return new NumberEval(rnum + 1.);
     }
-    public ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
-        switch (args.length) {
-            case 1:
-                return evaluate(srcRowIndex, srcColumnIndex, args[0]);
-            case 0:
-                return new NumberEval(srcColumnIndex+1.);
-        }
-        return ErrorEval.VALUE_INVALID;
-    }
 }
diff --git a/poi/src/main/java/org/apache/poi/ss/formula/functions/Even.java b/poi/src/main/java/org/apache/poi/ss/formula/functions/Even.java
deleted file mode 100644 (file)
index f691265..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.ss.formula.functions;
-
-
-/**
- * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
- *
- */
-public final class Even extends NumericFunction.OneArg {
-
-       private static final long PARITY_MASK = 0xFFFFFFFFFFFFFFFEL;
-
-       protected double evaluate(double d) {
-               if (d==0) {
-                       return 0;
-               }
-               long result;
-               if (d>0) {
-                       result = calcEven(d);
-               } else {
-                       result = -calcEven(-d);
-               }
-               return result;
-       }
-
-       private static long calcEven(double d) {
-               long x = ((long) d) & PARITY_MASK;
-               if (x == d) {
-                       return x;
-               }
-               return x + 2;
-       }
-}
index dbb1695ba7f23ad6b03fe66244369a49b76a12bc..6ad247f4f5929e2c7dfd79326103de6e2fa05526 100644 (file)
@@ -19,12 +19,15 @@ package org.apache.poi.ss.formula.functions;
 
 import org.apache.poi.ss.formula.eval.ErrorEval;
 import org.apache.poi.ss.formula.eval.ValueEval;
+import org.apache.poi.util.Removal;
 
 /**
  * Convenience base class for functions that only take zero arguments.
  *
- * @author Josh Micich
+ * @deprecated replaced by lambda expressions in 5.0.1
  */
+@Deprecated
+@Removal(version = "6.0.0")
 public abstract class Fixed0ArgFunction implements Function0Arg {
        public final ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
                if (args.length != 0) {
diff --git a/poi/src/main/java/org/apache/poi/ss/formula/functions/Log.java b/poi/src/main/java/org/apache/poi/ss/formula/functions/Log.java
new file mode 100644 (file)
index 0000000..d477405
--- /dev/null
@@ -0,0 +1,50 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+package org.apache.poi.ss.formula.functions;
+
+import org.apache.poi.ss.formula.eval.ErrorEval;
+import org.apache.poi.ss.formula.eval.EvaluationException;
+import org.apache.poi.ss.formula.eval.NumberEval;
+import org.apache.poi.ss.formula.eval.ValueEval;
+
+public class Log {
+    private static final double TEN = 10.0;
+    private static final double LOG_10_TO_BASE_e = Math.log(TEN);
+
+    public static ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
+        if (args.length != 1 && args.length != 2) {
+            return ErrorEval.VALUE_INVALID;
+        }
+
+        try {
+            double d0 = NumericFunction.singleOperandEvaluate(args[0], srcRowIndex, srcColumnIndex);
+            double result;
+            if (args.length == 1) {
+                result = Math.log(d0) / LOG_10_TO_BASE_e;
+            } else {
+                double d1 = NumericFunction.singleOperandEvaluate(args[1], srcRowIndex, srcColumnIndex);
+                double logE = Math.log(d0);
+                result = (Double.compare(d1, Math.E) == 0) ? logE : (logE / Math.log(d1));
+            }
+            NumericFunction.checkValue(result);
+            return new NumberEval(result);
+        } catch (EvaluationException e) {
+            return e.getErrorEval();
+        }
+    }
+}
index c88923faf6217fd30cb2c00a568b6674380d5ce3..7b33de57ecc9b4f829004496f02a86135fa4feb0 100644 (file)
@@ -51,6 +51,12 @@ final class MathX {
         return round(n, p, java.math.RoundingMode.HALF_UP);
     }
 
+    public static double round(double n, double p) {
+        return round(n, (int)p);
+    }
+
+
+
     /**
      * Returns a value rounded-up to p digits after decimal.
      * If p is negative, then the number is rounded to
@@ -70,6 +76,11 @@ final class MathX {
         return round(n, p, java.math.RoundingMode.UP);
     }
 
+    public static double roundUp(double n, double p) {
+        return roundUp(n, (int)p);
+    }
+
+
     /**
      * Returns a value rounded to p digits after decimal.
      * If p is negative, then the number is rounded to
@@ -88,7 +99,11 @@ final class MathX {
     public static double roundDown(double n, int p) {
         return round(n, p, java.math.RoundingMode.DOWN);
     }
-    
+
+    public static double roundDown(double n, double p) {
+        return roundDown(n, (int)p);
+    }
+
     private static double round(double n, int p, java.math.RoundingMode rounding) {
         if (Double.isNaN(n) || Double.isInfinite(n)) {
             return Double.NaN;
@@ -273,6 +288,10 @@ final class MathX {
         return d;
     }
 
+    public static double factorial(double d) {
+        return factorial((int)d);
+    }
+
 
     /**
      * returns the remainder resulting from operation:
index 32248677043b2ae00bf347bb53596e730be1f73f..15db4741631a961e86cf6ed8a86e5e78ccb330bb 100644 (file)
@@ -22,12 +22,9 @@ import org.apache.poi.ss.formula.eval.ValueEval;
 
 /**
  * Implementation of Excel function NA()
- *
- * @author Josh Micich
  */
-public final class Na extends Fixed0ArgFunction {
-
-       public ValueEval evaluate(int srcCellRow, int srcCellCol) {
-               return ErrorEval.NA;
+public final class Na {
+       public static ValueEval evaluate(ValueEval[] args, int srcCellRow, int srcCellCol) {
+               return args.length != 0 ? ErrorEval.VALUE_INVALID : ErrorEval.NA;
        }
 }
index e0fcf22fd32ff0848a8be9f879d9b768a36a6676..c840d923a2b33c04dff43401c08ddd3efac97395 100644 (file)
@@ -19,18 +19,19 @@ package org.apache.poi.ss.formula.functions;
 
 import java.util.Date;
 
+import org.apache.poi.ss.formula.eval.ErrorEval;
 import org.apache.poi.ss.formula.eval.NumberEval;
 import org.apache.poi.ss.formula.eval.ValueEval;
 import org.apache.poi.ss.usermodel.DateUtil;
 
 /**
  * Implementation of Excel NOW() Function
- *
- * @author Frank Taffelt
  */
-public final class Now extends Fixed0ArgFunction {
-
-       public ValueEval evaluate(int srcRowIndex, int srcColumnIndex) {
+public final class Now {
+       public static ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
+               if (args.length != 0) {
+                       return ErrorEval.VALUE_INVALID;
+               }
                Date now = new Date(System.currentTimeMillis());
                return new NumberEval(DateUtil.getExcelDate(now));
        }
index b0e85d903efd4b5b5a8dcb8e192bf14ebaf5572e..74597910b523ddc88787c4f6e5ead7b1a2c14df0 100644 (file)
 
 package org.apache.poi.ss.formula.functions;
 
+import static org.apache.poi.ss.formula.eval.ErrorEval.VALUE_INVALID;
+
 import org.apache.poi.ss.formula.eval.*;
 
-/**
- * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
- * @author Josh Micich
- * @author Stephen Wolke (smwolke at geistig.com)
- */
 public abstract class NumericFunction implements Function {
 
-       static final double ZERO = 0.0;
-       static final double TEN = 10.0;
-       static final double LOG_10_TO_BASE_e = Math.log(TEN);
+       private static final double ZERO = 0.0;
+       private static final double TEN = 10.0;
+       private static final double LOG_10_TO_BASE_e = Math.log(TEN);
+       private static final long PARITY_MASK = 0xFFFFFFFFFFFFFFFEL;
+
 
        protected static double singleOperandEvaluate(ValueEval arg, int srcRowIndex, int srcColumnIndex) throws EvaluationException {
                if (arg == null) {
@@ -41,7 +40,7 @@ public abstract class NumericFunction implements Function {
        }
 
        /**
-        * @throws EvaluationException (#NUM!) if <tt>result</tt> is <tt>NaN</tt> or <tt>Infinity</tt>
+        * @throws EvaluationException (#NUM!) if <tt>result</tt> is {@code NaN} or {@code Infinity}
         */
        public static void checkValue(double result) throws EvaluationException {
                if (Double.isNaN(result) || Double.isInfinite(result)) {
@@ -62,432 +61,179 @@ public abstract class NumericFunction implements Function {
 
        protected abstract double eval(ValueEval[] args, int srcCellRow, int srcCellCol) throws EvaluationException;
 
-       /* -------------------------------------------------------------------------- */
-       // intermediate sub-classes (one-arg, two-arg and multi-arg)
-
-       public static abstract class OneArg extends Fixed1ArgFunction {
-               protected OneArg() {
-                       // no fields to initialise
-               }
-               public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) {
-                       double result;
-                       try {
-                               double d = singleOperandEvaluate(arg0, srcRowIndex, srcColumnIndex);
-                               result = evaluate(d);
-                               checkValue(result);
-                       } catch (EvaluationException e) {
-                               return e.getErrorEval();
-                       }
-                       return new NumberEval(result);
+       public static final Function ABS = oneDouble(Math::abs);
+       public static final Function ACOS = oneDouble(Math::acos);
+       public static final Function ACOSH = oneDouble(MathX::acosh);
+       public static final Function ASIN = oneDouble(Math::asin);
+       public static final Function ASINH = oneDouble(MathX::asinh);
+       public static final Function ATAN = oneDouble(Math::atan);
+       public static final Function ATANH = oneDouble(MathX::atanh);
+       public static final Function COS = oneDouble(Math::cos);
+       public static final Function COSH = oneDouble(MathX::cosh);
+       public static final Function DEGREES = oneDouble(Math::toDegrees);
+       public static final Function DOLLAR = NumericFunction::evaluateDollar;
+
+       private static ValueEval evaluateDollar(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
+               if (args.length != 1 && args.length != 2) {
+                       return ErrorEval.VALUE_INVALID;
                }
-               protected final double eval(ValueEval[] args, int srcCellRow, int srcCellCol) throws EvaluationException {
-                       if (args.length != 1) {
-                               throw new EvaluationException(ErrorEval.VALUE_INVALID);
+               try {
+                       double val = singleOperandEvaluate(args[0], srcRowIndex, srcColumnIndex);
+                       double d1 = args.length == 1 ? 2.0 : singleOperandEvaluate(args[1], srcRowIndex, srcColumnIndex);
+
+                       // second arg converts to int by truncating toward zero
+                       int nPlaces = (int)d1;
+
+                       if (nPlaces > 127) {
+                               return VALUE_INVALID;
                        }
-                       double d = singleOperandEvaluate(args[0], srcCellRow, srcCellCol);
-                       return evaluate(d);
+
+                       // TODO - DOLLAR() function impl is NQR
+                       // result should be StringEval, with leading '$' and thousands separators
+                       // current junits are asserting incorrect behaviour
+                       return new NumberEval(val);
+               }catch (EvaluationException e) {
+                       return e.getErrorEval();
                }
-               protected abstract double evaluate(double d) throws EvaluationException;
        }
 
-       public static abstract class TwoArg extends Fixed2ArgFunction {
-               protected TwoArg() {
-                       // no fields to initialise
-               }
+       public static final Function EXP = oneDouble(d -> Math.pow(Math.E, d));
+       public static final Function FACT = oneDouble(MathX::factorial);
+       public static final Function INT = oneDouble(d -> Math.round(d-0.5));
+       public static final Function LN = oneDouble(Math::log);
+       public static final Function LOG10 = oneDouble(d -> Math.log(d) / LOG_10_TO_BASE_e);
+       public static final Function RADIANS = oneDouble(Math::toRadians);
+       public static final Function SIGN = oneDouble(MathX::sign);
+       public static final Function SIN = oneDouble(Math::sin);
+       public static final Function SINH = oneDouble(MathX::sinh);
+       public static final Function SQRT = oneDouble(Math::sqrt);
+       public static final Function TAN = oneDouble(Math::tan);
+       public static final Function TANH = oneDouble(MathX::tanh);
 
+       /* -------------------------------------------------------------------------- */
 
-               public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1) {
-                       double result;
-                       try {
-                               double d0 = singleOperandEvaluate(arg0, srcRowIndex, srcColumnIndex);
-                               double d1 = singleOperandEvaluate(arg1, srcRowIndex, srcColumnIndex);
-                               result =  evaluate(d0, d1);
-                               checkValue(result);
-                       } catch (EvaluationException e) {
-                               return e.getErrorEval();
-                       }
+       public static final Function ATAN2 = twoDouble((d0, d1) ->
+               (d0 == ZERO && d1 == ZERO) ? ErrorEval.DIV_ZERO : Math.atan2(d1, d0)
+       );
+
+       public static final Function CEILING = twoDouble(MathX::ceiling);
+
+       public static final Function COMBIN = twoDouble((d0, d1) ->
+               (d0 > Integer.MAX_VALUE || d1 > Integer.MAX_VALUE) ? ErrorEval.NUM_ERROR : MathX.nChooseK((int) d0, (int) d1));
+
+       public static final Function FLOOR = twoDouble((d0, d1) ->
+               (d1 == ZERO) ? (d0 == ZERO ? ZERO : ErrorEval.DIV_ZERO) : MathX.floor(d0, d1));
+
+       public static final Function MOD = twoDouble((d0, d1) ->
+               (d1 == ZERO) ? ErrorEval.DIV_ZERO : MathX.mod(d0, d1));
+
+       public static final Function POWER = twoDouble(Math::pow);
+
+       public static final Function ROUND = twoDouble(MathX::round);
+       public static final Function ROUNDDOWN = twoDouble(MathX::roundDown);
+       public static final Function ROUNDUP = twoDouble(MathX::roundUp);
+       public static final Function TRUNC = NumericFunction::evaluateTrunc;
+
+       private static ValueEval evaluateTrunc(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
+               if (args.length != 1 && args.length != 2) {
+                       return ErrorEval.VALUE_INVALID;
+               }
+               try {
+                       double d0 = singleOperandEvaluate(args[0], srcRowIndex, srcColumnIndex);
+                       double d1 = args.length == 1 ? 0 : singleOperandEvaluate(args[1], srcRowIndex, srcColumnIndex);
+                       double result = MathX.roundDown(d0, d1);
+                       checkValue(result);
                        return new NumberEval(result);
+               }catch (EvaluationException e) {
+                       return e.getErrorEval();
                }
-
-               protected abstract double evaluate(double d0, double d1) throws EvaluationException;
        }
 
        /* -------------------------------------------------------------------------- */
 
-       public static final Function ABS = new OneArg() {
-               protected double evaluate(double d) {
-                       return Math.abs(d);
-               }
-       };
-       public static final Function ACOS = new OneArg() {
-               protected double evaluate(double d) {
-                       return Math.acos(d);
-               }
-       };
-       public static final Function ACOSH = new OneArg() {
-               protected double evaluate(double d) {
-                       return MathX.acosh(d);
-               }
-       };
-       public static final Function ASIN = new OneArg() {
-               protected double evaluate(double d) {
-                       return Math.asin(d);
-               }
-       };
-       public static final Function ASINH = new OneArg() {
-               protected double evaluate(double d) {
-                       return MathX.asinh(d);
-               }
-       };
-       public static final Function ATAN = new OneArg() {
-               protected double evaluate(double d) {
-                       return Math.atan(d);
-               }
-       };
-       public static final Function ATANH = new OneArg() {
-               protected double evaluate(double d) {
-                       return MathX.atanh(d);
-               }
-       };
-       public static final Function COS = new OneArg() {
-               protected double evaluate(double d) {
-                       return Math.cos(d);
-               }
-       };
-       public static final Function COSH = new OneArg() {
-               protected double evaluate(double d) {
-                       return MathX.cosh(d);
-               }
-       };
-       public static final Function DEGREES = new OneArg() {
-               protected double evaluate(double d) {
-                       return Math.toDegrees(d);
-               }
-       };
-       static final NumberEval DOLLAR_ARG2_DEFAULT = new NumberEval(2.0);
-       public static final Function DOLLAR = new Var1or2ArgFunction() {
-               public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) {
-                       return evaluate(srcRowIndex, srcColumnIndex, arg0, DOLLAR_ARG2_DEFAULT);
-               }
+       public static final Function LOG = Log::evaluate;
 
-               public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0,
-                               ValueEval arg1) {
-                       double val;
-                       double d1;
-                       try {
-                               val = singleOperandEvaluate(arg0, srcRowIndex, srcColumnIndex);
-                               d1 = singleOperandEvaluate(arg1, srcRowIndex, srcColumnIndex);
-                       } catch (EvaluationException e) {
-                               return e.getErrorEval();
-                       }
-                       // second arg converts to int by truncating toward zero
-                       int nPlaces = (int)d1;
+       static final NumberEval PI_EVAL = new NumberEval(Math.PI);
+       public static final Function PI = NumericFunction::evaluatePI;
 
-                       if (nPlaces > 127) {
-                               return ErrorEval.VALUE_INVALID;
-                       }
+       private static ValueEval evaluatePI(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
+               return (args.length != 0) ? ErrorEval.VALUE_INVALID : PI_EVAL;
+       }
 
+       public static final Function RAND = NumericFunction::evaluateRand;
 
-                       // TODO - DOLLAR() function impl is NQR
-                       // result should be StringEval, with leading '$' and thousands separators
-                       // current junits are asserting incorrect behaviour
-                       return new NumberEval(val);
-               }
-       };
-       public static final Function EXP = new OneArg() {
-               protected double evaluate(double d) {
-                       return Math.pow(Math.E, d);
-               }
-       };
-       public static final Function FACT = new OneArg() {
-               protected double evaluate(double d) {
-                       return MathX.factorial((int)d);
-               }
-       };
-       public static final Function INT = new OneArg() {
-               protected double evaluate(double d) {
-                       return Math.round(d-0.5);
-               }
-       };
-       public static final Function LN = new OneArg() {
-               protected double evaluate(double d) {
-                       return Math.log(d);
-               }
-       };
-       public static final Function LOG10 = new OneArg() {
-               protected double evaluate(double d) {
-                       return Math.log(d) / LOG_10_TO_BASE_e;
-               }
-       };
-       public static final Function RADIANS = new OneArg() {
-               protected double evaluate(double d) {
-                       return Math.toRadians(d);
-               }
-       };
-       public static final Function SIGN = new OneArg() {
-               protected double evaluate(double d) {
-                       return MathX.sign(d);
-               }
-       };
-       public static final Function SIN = new OneArg() {
-               protected double evaluate(double d) {
-                       return Math.sin(d);
-               }
-       };
-       public static final Function SINH = new OneArg() {
-               protected double evaluate(double d) {
-                       return MathX.sinh(d);
-               }
-       };
-       public static final Function SQRT = new OneArg() {
-               protected double evaluate(double d) {
-                       return Math.sqrt(d);
-               }
-       };
+       private static ValueEval evaluateRand(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
+               return (args.length != 0) ? ErrorEval.VALUE_INVALID : new NumberEval(Math.random());
+       }
 
-       public static final Function TAN = new OneArg() {
-               protected double evaluate(double d) {
-                       return Math.tan(d);
-               }
-       };
-       public static final Function TANH = new OneArg() {
-               protected double evaluate(double d) {
-                       return MathX.tanh(d);
-               }
-       };
+       public static final Function POISSON = Poisson::evaluate;
 
-       /* -------------------------------------------------------------------------- */
+       public static final Function ODD = oneDouble(NumericFunction::evaluateOdd);
 
-       public static final Function ATAN2 = new TwoArg() {
-               protected double evaluate(double d0, double d1) throws EvaluationException {
-                       if (d0 == ZERO && d1 == ZERO) {
-                               throw new EvaluationException(ErrorEval.DIV_ZERO);
-                       }
-                       return Math.atan2(d1, d0);
-               }
-       };
-       public static final Function CEILING = new TwoArg() {
-               protected double evaluate(double d0, double d1) {
-                       return MathX.ceiling(d0, d1);
-               }
-       };
-       public static final Function COMBIN = new TwoArg() {
-               protected double evaluate(double d0, double d1) throws EvaluationException {
-                       if (d0 > Integer.MAX_VALUE || d1 > Integer.MAX_VALUE) {
-                               throw new EvaluationException(ErrorEval.NUM_ERROR);
-                       }
-                       return  MathX.nChooseK((int) d0, (int) d1);
-               }
-       };
-       public static final Function FLOOR = new TwoArg() {
-               protected double evaluate(double d0, double d1) throws EvaluationException {
-                       if (d1 == ZERO) {
-                               if (d0 == ZERO) {
-                                       return ZERO;
-                               }
-                               throw new EvaluationException(ErrorEval.DIV_ZERO);
-                       }
-                       return MathX.floor(d0, d1);
+       private static double evaluateOdd(double d) {
+               if (d==0) {
+                       return 1;
                }
-       };
-       public static final Function MOD = new TwoArg() {
-               protected double evaluate(double d0, double d1) throws EvaluationException {
-                       if (d1 == ZERO) {
-                               throw new EvaluationException(ErrorEval.DIV_ZERO);
-                       }
-                       return MathX.mod(d0, d1);
-               }
-       };
-       public static final Function POWER = new TwoArg() {
-               protected double evaluate(double d0, double d1) {
-                       return Math.pow(d0, d1);
-               }
-       };
-       public static final Function ROUND = new TwoArg() {
-               protected double evaluate(double d0, double d1) {
-                       return MathX.round(d0, (int)d1);
-               }
-       };
-       public static final Function ROUNDDOWN = new TwoArg() {
-               protected double evaluate(double d0, double d1) {
-                       return MathX.roundDown(d0, (int)d1);
-               }
-       };
-       public static final Function ROUNDUP = new TwoArg() {
-               protected double evaluate(double d0, double d1) {
-                       return MathX.roundUp(d0, (int)d1);
-               }
-       };
-       static final NumberEval TRUNC_ARG2_DEFAULT = new NumberEval(0);
-       public static final Function TRUNC = new Var1or2ArgFunction() {
+               double dpm = Math.abs(d)+1;
+               long x = ((long) dpm) & PARITY_MASK;
+               return MathX.sign(d) * ((Double.compare(x, dpm) == 0) ? x-1 : x+1);
+       }
 
-               public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) {
-                       return evaluate(srcRowIndex, srcColumnIndex, arg0, TRUNC_ARG2_DEFAULT);
-               }
 
-               public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1) {
-                       double result;
-                       try {
-                               double d0 = singleOperandEvaluate(arg0, srcRowIndex, srcColumnIndex);
-                               double d1 = singleOperandEvaluate(arg1, srcRowIndex, srcColumnIndex);
-                               result = MathX.roundDown(d0, (int)d1);
-                               checkValue(result);
-                       }catch (EvaluationException e) {
-                               return e.getErrorEval();
-                       }
-                       return new NumberEval(result);
+       public static final Function EVEN = oneDouble(NumericFunction::evaluateEven);
+
+       private static double evaluateEven(double d) {
+               if (d==0) {
+                       return 0;
                }
-       };
 
-       /* -------------------------------------------------------------------------- */
+               double dpm = Math.abs(d);
+               long x = ((long) dpm) & PARITY_MASK;
+               return MathX.sign(d) * ((Double.compare(x, dpm) == 0) ? x : (x + 2));
+       }
 
-       private static final class Log extends Var1or2ArgFunction {
-               public Log() {
-                       // no instance fields
-               }
-               public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) {
-                       double result;
-                       try {
-                               double d0 = NumericFunction.singleOperandEvaluate(arg0, srcRowIndex, srcColumnIndex);
-                               result = Math.log(d0) / LOG_10_TO_BASE_e;
-                               NumericFunction.checkValue(result);
-                       } catch (EvaluationException e) {
-                               return e.getErrorEval();
+
+       private interface OneDoubleIf {
+               double apply(double d);
+       }
+
+       private static Function oneDouble(OneDoubleIf doubleFun) {
+               return (args, srcCellRow, srcCellCol) -> {
+                       if (args.length != 1) {
+                               return VALUE_INVALID;
                        }
-                       return new NumberEval(result);
-               }
-               public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0,
-                               ValueEval arg1) {
-                       double result;
                        try {
-                               double d0 = NumericFunction.singleOperandEvaluate(arg0, srcRowIndex, srcColumnIndex);
-                               double d1 = NumericFunction.singleOperandEvaluate(arg1, srcRowIndex, srcColumnIndex);
-                               double logE = Math.log(d0);
-                if (Double.compare(d1, Math.E) == 0) {
-                                       result = logE;
-                               } else {
-                                       result = logE / Math.log(d1);
-                               }
-                               NumericFunction.checkValue(result);
+                               double d = singleOperandEvaluate(args[0], srcCellRow, srcCellCol);
+                               double res = doubleFun.apply(d);
+                               return (Double.isNaN(res) || Double.isInfinite(res)) ? ErrorEval.NUM_ERROR : new NumberEval(res);
                        } catch (EvaluationException e) {
                                return e.getErrorEval();
                        }
-                       return new NumberEval(result);
-               }
+               };
        }
 
-       public static final Function LOG = new Log();
-
-       static final NumberEval PI_EVAL = new NumberEval(Math.PI);
-       public static final Function PI = new Fixed0ArgFunction() {
-               public ValueEval evaluate(int srcRowIndex, int srcColumnIndex) {
-                       return PI_EVAL;
-               }
-       };
-       public static final Function RAND = new Fixed0ArgFunction() {
-               public ValueEval evaluate(int srcRowIndex, int srcColumnIndex) {
-                       return new NumberEval(Math.random());
-               }
-       };
-    public static final Function POISSON = new Fixed3ArgFunction() {
-
-        private static final double DEFAULT_RETURN_RESULT =1;
-
-        /**
-         * This checks is x = 0 and the mean = 0.
-         * Excel currently returns the value 1 where as the
-         * maths common implementation will error.
-         * @param x  The number.
-         * @param mean The mean.
-         * @return If a default value should be returned.
-         */
-        private boolean isDefaultResult(double x, double mean) {
-
-            if ( x == 0 && mean == 0 ) {
-                return true;
-            }
-            return false;
-        }
-
-        private boolean checkArgument(double aDouble) throws EvaluationException {
-
-            NumericFunction.checkValue(aDouble);
-
-            // make sure that the number is positive
-            if (aDouble < 0) {
-                throw new EvaluationException(ErrorEval.NUM_ERROR);
-            }
-
-            return true;
-        }
-
-        private double probability(int k, double lambda) {
-            return Math.pow(lambda, k) * Math.exp(-lambda) / factorial(k);
-        }
-
-        private double cumulativeProbability(int x, double lambda) {
-            double result = 0;
-            for(int k = 0; k <= x; k++){
-                result += probability(k, lambda);
-            }
-            return result;
-        }
-
-        /** All long-representable factorials */
-        private final long[] FACTORIALS = new long[] {
-                           1l,                  1l,                   2l,
-                           6l,                 24l,                 120l,
-                         720l,               5040l,               40320l,
-                      362880l,            3628800l,            39916800l,
-                   479001600l,         6227020800l,         87178291200l,
-               1307674368000l,     20922789888000l,     355687428096000l,
-            6402373705728000l, 121645100408832000l, 2432902008176640000l };
-
-
-        public long factorial(final int n) {
-            if (n < 0 || n > 20) {
-                throw new IllegalArgumentException("Valid argument should be in the range [0..20]");
-            }
-            return FACTORIALS[n];
-        }
-
-        public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1, ValueEval arg2) {
-
-            // arguments/result for this function
-            double mean=0;
-            double x=0;
-            boolean cumulative = ((BoolEval)arg2).getBooleanValue();
-            double result=0;
-
-            try {
-                               x = NumericFunction.singleOperandEvaluate(arg0, srcRowIndex, srcColumnIndex);
-                               mean = NumericFunction.singleOperandEvaluate(arg1, srcRowIndex, srcColumnIndex);
-
-                // check for default result : excel implementation for 0,0
-                // is different to Math Common.
-                if (isDefaultResult(x,mean)) {
-                    return new NumberEval(DEFAULT_RETURN_RESULT);
-                }
-                // check the arguments : as per excel function def
-                checkArgument(x);
-                checkArgument(mean);
-
-                // truncate x : as per excel function def
-                if ( cumulative ) {
-                    result = cumulativeProbability((int)x, mean);
-                } else {
-                    result = probability((int)x, mean);
-                }
-
-                // check the result
-                NumericFunction.checkValue(result);
+       private interface TwoDoubleIf {
+               Object apply(double d1, double d2);
+       }
 
+       private static Function twoDouble(TwoDoubleIf doubleFun) {
+               return (args, srcCellRow, srcCellCol) -> {
+                       if (args.length != 2) {
+                               return VALUE_INVALID;
+                       }
+                       try {
+                               double d1 = singleOperandEvaluate(args[0], srcCellRow, srcCellCol);
+                               double d2 = singleOperandEvaluate(args[1], srcCellRow, srcCellCol);
+                               Object res = doubleFun.apply(d1, d2);
+                               if (res instanceof ErrorEval) {
+                                       return (ErrorEval)res;
+                               }
+                               assert(res instanceof Double);
+                               double d = (Double)res;
+                               return (Double.isNaN(d) || Double.isInfinite(d)) ? ErrorEval.NUM_ERROR : new NumberEval(d);
                        } catch (EvaluationException e) {
                                return e.getErrorEval();
                        }
-
-            return new NumberEval(result);
-
-        }
-    };
+               };
+       }
 }
diff --git a/poi/src/main/java/org/apache/poi/ss/formula/functions/Odd.java b/poi/src/main/java/org/apache/poi/ss/formula/functions/Odd.java
deleted file mode 100644 (file)
index 6762fcb..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.ss.formula.functions;
-
-/**
- * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
- *
- */
-public final class Odd extends NumericFunction.OneArg {
-       private static final long PARITY_MASK = 0xFFFFFFFFFFFFFFFEL;
-
-       protected double evaluate(double d) {
-               if (d==0) {
-                       return 1;
-               }
-               return (d>0) ? calcOdd(d) : -calcOdd(-d);
-       }
-
-       private static long calcOdd(double d) {
-               double dpm1 = d+1;
-               long x = ((long) dpm1) & PARITY_MASK;
-               return ( Double.compare(x, dpm1) == 0 ) ? x-1 : x+1;
-       }
-}
diff --git a/poi/src/main/java/org/apache/poi/ss/formula/functions/Poisson.java b/poi/src/main/java/org/apache/poi/ss/formula/functions/Poisson.java
new file mode 100644 (file)
index 0000000..8e67a6c
--- /dev/null
@@ -0,0 +1,115 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+package org.apache.poi.ss.formula.functions;
+
+import org.apache.poi.ss.formula.eval.BoolEval;
+import org.apache.poi.ss.formula.eval.ErrorEval;
+import org.apache.poi.ss.formula.eval.EvaluationException;
+import org.apache.poi.ss.formula.eval.NumberEval;
+import org.apache.poi.ss.formula.eval.ValueEval;
+
+public class Poisson {
+
+    private static final double DEFAULT_RETURN_RESULT =1;
+
+    /** All long-representable factorials */
+    private static final long[] FACTORIALS = {
+        1L,                  1L,                   2L,
+        6L,                 24L,                 120L,
+        720L,               5040L,               40320L,
+        362880L,            3628800L,            39916800L,
+        479001600L,         6227020800L,         87178291200L,
+        1307674368000L,     20922789888000L,     355687428096000L,
+        6402373705728000L, 121645100408832000L, 2432902008176640000L };
+
+    /**
+     * This checks is x = 0 and the mean = 0.
+     * Excel currently returns the value 1 where as the
+     * maths common implementation will error.
+     * @param x  The number.
+     * @param mean The mean.
+     * @return If a default value should be returned.
+     */
+    private static boolean isDefaultResult(double x, double mean) {
+        return x == 0 && mean == 0;
+    }
+
+    private static void checkArgument(double aDouble) throws EvaluationException {
+        NumericFunction.checkValue(aDouble);
+
+        // make sure that the number is positive
+        if (aDouble < 0) {
+            throw new EvaluationException(ErrorEval.NUM_ERROR);
+        }
+    }
+
+    private static double probability(int k, double lambda) {
+        return Math.pow(lambda, k) * Math.exp(-lambda) / factorial(k);
+    }
+
+    private static double cumulativeProbability(int x, double lambda) {
+        double result = 0;
+        for(int k = 0; k <= x; k++){
+            result += probability(k, lambda);
+        }
+        return result;
+    }
+
+    private static long factorial(final int n) {
+        if (n < 0 || n > 20) {
+            throw new IllegalArgumentException("Valid argument should be in the range [0..20]");
+        }
+        return FACTORIALS[n];
+    }
+
+    public static ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
+        if (args.length != 3) {
+            return ErrorEval.VALUE_INVALID;
+        }
+        ValueEval arg0 = args[0];
+        ValueEval arg1 = args[1];
+        ValueEval arg2 = args[2];
+
+        try {
+            // arguments/result for this function
+            double x = NumericFunction.singleOperandEvaluate(arg0, srcRowIndex, srcColumnIndex);
+            double mean = NumericFunction.singleOperandEvaluate(arg1, srcRowIndex, srcColumnIndex);
+
+            // check for default result : excel implementation for 0,0
+            // is different to Math Common.
+            if (isDefaultResult(x,mean)) {
+                return new NumberEval(DEFAULT_RETURN_RESULT);
+            }
+            // check the arguments : as per excel function def
+            checkArgument(x);
+            checkArgument(mean);
+
+            // truncate x : as per excel function def
+            boolean cumulative = ((BoolEval)arg2).getBooleanValue();
+            double result = cumulative ? cumulativeProbability((int) x, mean) : probability((int) x, mean);
+
+            // check the result
+            NumericFunction.checkValue(result);
+
+            return new NumberEval(result);
+        } catch (EvaluationException e) {
+            return e.getErrorEval();
+        }
+    }
+
+}
index 17d7acfdfe1476341a12dfd0f92bd1551624d2b4..b8786f2b0b97256dc54f190e56b729bc87eee89b 100644 (file)
@@ -26,18 +26,19 @@ import org.apache.poi.ss.formula.eval.ValueEval;
 /**
  * Implementation for the Excel function ROW
  */
-public final class RowFunc implements Function0Arg, Function1Arg {
+public final class RowFunc {
+    public static ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
+        if (args.length > 1) {
+            return ErrorEval.VALUE_INVALID;
+        }
 
-    public ValueEval evaluate(int srcRowIndex, int srcColumnIndex) {
-        return new NumberEval(srcRowIndex+1.);
-    }
-    public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) {
         int rnum;
-
-        if (arg0 instanceof AreaEval) {
-            rnum = ((AreaEval) arg0).getFirstRow();
-        } else if (arg0 instanceof RefEval) {
-            rnum = ((RefEval) arg0).getRow();
+        if (args.length == 0) {
+            rnum = srcRowIndex;
+        } else if (args[0] instanceof AreaEval) {
+            rnum = ((AreaEval) args[0]).getFirstRow();
+        } else if (args[0] instanceof RefEval) {
+            rnum = ((RefEval) args[0]).getRow();
         } else {
             // anything else is not valid argument
             return ErrorEval.VALUE_INVALID;
@@ -45,13 +46,4 @@ public final class RowFunc implements Function0Arg, Function1Arg {
 
         return new NumberEval(rnum + 1.);
     }
-    public ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
-        switch (args.length) {
-            case 1:
-                return evaluate(srcRowIndex, srcColumnIndex, args[0]);
-            case 0:
-              return new NumberEval(srcRowIndex+1.);
-        }
-        return ErrorEval.VALUE_INVALID;
-    }
 }
index 677d1f0e4807f68734769bd480846cba44f2050e..5c38a6915106f5db802f80dd8d95a77693c4d47b 100644 (file)
@@ -19,6 +19,7 @@ package org.apache.poi.ss.formula.functions;
 
 import java.util.Calendar;
 
+import org.apache.poi.ss.formula.eval.ErrorEval;
 import org.apache.poi.ss.formula.eval.NumberEval;
 import org.apache.poi.ss.formula.eval.ValueEval;
 import org.apache.poi.ss.usermodel.DateUtil;
@@ -27,8 +28,11 @@ import org.apache.poi.util.LocaleUtil;
 /**
  * Implementation of Excel TODAY() Function<br>
  */
-public final class Today extends Fixed0ArgFunction {
-       public ValueEval evaluate(int srcRowIndex, int srcColumnIndex) {
+public final class Today {
+       public static ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
+               if (args.length != 0) {
+                       return ErrorEval.VALUE_INVALID;
+               }
                Calendar now = LocaleUtil.getLocaleCalendar();
                now.clear(Calendar.HOUR);
         now.set(Calendar.HOUR_OF_DAY,0);
index eb2812e0e431bb4e476880e6f97dd974762fb9b2..8250d4bd78d74fd53fb828c7e93479db0fdabeda 100644 (file)
@@ -24,14 +24,12 @@ import org.junit.jupiter.api.Test;
 
 /**
  * Tests for ROW(), ROWS(), COLUMN(), COLUMNS()
- *
- * @author Josh Micich
  */
 final class TestRowCol {
 
        @Test
        void testCol() {
-               Function target = new Column();
+               Function target = Column::evaluate;
                {
                        ValueEval[] args = { EvalFactory.createRefEval("C5"), };
                        double actual = NumericFunctionInvoker.invoke(target, args);
@@ -46,7 +44,7 @@ final class TestRowCol {
 
        @Test
        void testRow() {
-               Function target = new RowFunc();
+               Function target = RowFunc::evaluate;
                {
                        ValueEval[] args = { EvalFactory.createRefEval("C5"), };
                        double actual = NumericFunctionInvoker.invoke(target, args);