mirror of https://github.com/apache/poi.git
replace over engineered inner classes with lambdas/method references
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1888743 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
3c03974499
commit
240b02daec
|
@ -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
|
||||
|
|
|
@ -32,10 +32,10 @@ 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,7 +160,8 @@ public interface ArrayFunction {
|
|||
return new CacheAreaEval(srcRowIndex, srcColumnIndex, srcRowIndex + height - 1, srcColumnIndex + width - 1, vals);
|
||||
}
|
||||
|
||||
default ValueEval evaluateOneArrayArg(ValueEval arg0, int srcRowIndex, int srcColumnIndex,
|
||||
|
||||
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;
|
||||
|
@ -204,7 +215,6 @@ public interface ArrayFunction {
|
|||
}
|
||||
|
||||
return new CacheAreaEval(srcRowIndex, srcColumnIndex, srcRowIndex + height - 1, srcColumnIndex + width - 1, vals);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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 < amolweb at ya hoo dot com >
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -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 ValueEval evaluate(int srcRowIndex, int srcColumnIndex) {
|
||||
return new NumberEval(srcColumnIndex+1.);
|
||||
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, ValueEval arg0) {
|
||||
int rnum;
|
||||
|
||||
if (arg0 instanceof AreaEval) {
|
||||
rnum = ((AreaEval) arg0).getFirstColumn();
|
||||
} else if (arg0 instanceof RefEval) {
|
||||
rnum = ((RefEval) arg0).getColumn();
|
||||
int rnum;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 < amolweb at ya hoo dot com >
|
||||
*
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
@ -89,6 +100,10 @@ final class MathX {
|
|||
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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -17,18 +17,17 @@
|
|||
|
||||
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 < amolweb at ya hoo dot com >
|
||||
* @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 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;
|
||||
|
||||
public static abstract class OneArg extends Fixed1ArgFunction {
|
||||
protected OneArg() {
|
||||
// no fields to initialise
|
||||
private static ValueEval evaluateDollar(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
|
||||
if (args.length != 1 && args.length != 2) {
|
||||
return ErrorEval.VALUE_INVALID;
|
||||
}
|
||||
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);
|
||||
}
|
||||
protected final double eval(ValueEval[] args, int srcCellRow, int srcCellCol) throws EvaluationException {
|
||||
if (args.length != 1) {
|
||||
throw new EvaluationException(ErrorEval.VALUE_INVALID);
|
||||
}
|
||||
double d = singleOperandEvaluate(args[0], srcCellRow, srcCellCol);
|
||||
return evaluate(d);
|
||||
}
|
||||
protected abstract double evaluate(double d) throws EvaluationException;
|
||||
}
|
||||
double val = singleOperandEvaluate(args[0], srcRowIndex, srcColumnIndex);
|
||||
double d1 = args.length == 1 ? 2.0 : singleOperandEvaluate(args[1], srcRowIndex, srcColumnIndex);
|
||||
|
||||
public static abstract class TwoArg extends Fixed2ArgFunction {
|
||||
protected TwoArg() {
|
||||
// no fields to initialise
|
||||
}
|
||||
|
||||
|
||||
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();
|
||||
}
|
||||
return new NumberEval(result);
|
||||
}
|
||||
|
||||
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 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;
|
||||
|
||||
if (nPlaces > 127) {
|
||||
return ErrorEval.VALUE_INVALID;
|
||||
return VALUE_INVALID;
|
||||
}
|
||||
|
||||
|
||||
// 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();
|
||||
}
|
||||
};
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
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 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 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);
|
||||
}
|
||||
};
|
||||
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() {
|
||||
public static final Function ATAN2 = twoDouble((d0, d1) ->
|
||||
(d0 == ZERO && d1 == ZERO) ? ErrorEval.DIV_ZERO : Math.atan2(d1, d0)
|
||||
);
|
||||
|
||||
public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) {
|
||||
return evaluate(srcRowIndex, srcColumnIndex, arg0, TRUNC_ARG2_DEFAULT);
|
||||
}
|
||||
public static final Function CEILING = twoDouble(MathX::ceiling);
|
||||
|
||||
public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1) {
|
||||
double result;
|
||||
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(arg0, srcRowIndex, srcColumnIndex);
|
||||
double d1 = singleOperandEvaluate(arg1, srcRowIndex, srcColumnIndex);
|
||||
result = MathX.roundDown(d0, (int)d1);
|
||||
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();
|
||||
}
|
||||
return new NumberEval(result);
|
||||
}
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
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();
|
||||
}
|
||||
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);
|
||||
} catch (EvaluationException e) {
|
||||
return e.getErrorEval();
|
||||
}
|
||||
return new NumberEval(result);
|
||||
}
|
||||
}
|
||||
|
||||
public static final Function LOG = new Log();
|
||||
public static final Function LOG = Log::evaluate;
|
||||
|
||||
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() {
|
||||
public static final Function PI = NumericFunction::evaluatePI;
|
||||
|
||||
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 static ValueEval evaluatePI(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
|
||||
return (args.length != 0) ? ErrorEval.VALUE_INVALID : PI_EVAL;
|
||||
}
|
||||
|
||||
private boolean checkArgument(double aDouble) throws EvaluationException {
|
||||
public static final Function RAND = NumericFunction::evaluateRand;
|
||||
|
||||
NumericFunction.checkValue(aDouble);
|
||||
|
||||
// make sure that the number is positive
|
||||
if (aDouble < 0) {
|
||||
throw new EvaluationException(ErrorEval.NUM_ERROR);
|
||||
private static ValueEval evaluateRand(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
|
||||
return (args.length != 0) ? ErrorEval.VALUE_INVALID : new NumberEval(Math.random());
|
||||
}
|
||||
|
||||
return true;
|
||||
public static final Function POISSON = Poisson::evaluate;
|
||||
|
||||
public static final Function ODD = oneDouble(NumericFunction::evaluateOdd);
|
||||
|
||||
private static double evaluateOdd(double d) {
|
||||
if (d==0) {
|
||||
return 1;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
private double probability(int k, double lambda) {
|
||||
return Math.pow(lambda, k) * Math.exp(-lambda) / factorial(k);
|
||||
|
||||
public static final Function EVEN = oneDouble(NumericFunction::evaluateEven);
|
||||
|
||||
private static double evaluateEven(double d) {
|
||||
if (d==0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
private double cumulativeProbability(int x, double lambda) {
|
||||
double result = 0;
|
||||
for(int k = 0; k <= x; k++){
|
||||
result += probability(k, lambda);
|
||||
}
|
||||
return result;
|
||||
double dpm = Math.abs(d);
|
||||
long x = ((long) dpm) & PARITY_MASK;
|
||||
return MathX.sign(d) * ((Double.compare(x, dpm) == 0) ? x : (x + 2));
|
||||
}
|
||||
|
||||
/** 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];
|
||||
private interface OneDoubleIf {
|
||||
double apply(double d);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
private static Function oneDouble(OneDoubleIf doubleFun) {
|
||||
return (args, srcCellRow, srcCellCol) -> {
|
||||
if (args.length != 1) {
|
||||
return VALUE_INVALID;
|
||||
}
|
||||
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);
|
||||
|
||||
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);
|
||||
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();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 < amolweb at ya hoo dot com >
|
||||
*
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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 ValueEval evaluate(int srcRowIndex, int srcColumnIndex) {
|
||||
return new NumberEval(srcRowIndex+1.);
|
||||
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, ValueEval arg0) {
|
||||
int rnum;
|
||||
|
||||
if (arg0 instanceof AreaEval) {
|
||||
rnum = ((AreaEval) arg0).getFirstRow();
|
||||
} else if (arg0 instanceof RefEval) {
|
||||
rnum = ((RefEval) arg0).getRow();
|
||||
int rnum;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue