123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493 |
- /* ====================================================================
- 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.*;
-
- /**
- * @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);
-
- protected static double singleOperandEvaluate(ValueEval arg, int srcRowIndex, int srcColumnIndex) throws EvaluationException {
- if (arg == null) {
- throw new IllegalArgumentException("arg must not be null");
- }
- ValueEval ve = OperandResolver.getSingleValue(arg, srcRowIndex, srcColumnIndex);
- double result = OperandResolver.coerceValueToDouble(ve);
- checkValue(result);
- return result;
- }
-
- /**
- * @throws EvaluationException (#NUM!) if <tt>result</tt> is <tt>NaN</> or <tt>Infinity</tt>
- */
- public static void checkValue(double result) throws EvaluationException {
- if (Double.isNaN(result) || Double.isInfinite(result)) {
- throw new EvaluationException(ErrorEval.NUM_ERROR);
- }
- }
-
- public final ValueEval evaluate(ValueEval[] args, int srcCellRow, int srcCellCol) {
- double result;
- try {
- result = eval(args, srcCellRow, srcCellCol);
- checkValue(result);
- } catch (EvaluationException e) {
- return e.getErrorEval();
- }
- return new NumberEval(result);
- }
-
- 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);
- }
- 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;
- }
-
- 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;
- }
-
-
- // 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);
- }
- };
-
- 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 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 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);
- }
- };
-
- /* -------------------------------------------------------------------------- */
-
- 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();
-
- 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);
-
- } catch (EvaluationException e) {
- return e.getErrorEval();
- }
-
- return new NumberEval(result);
-
- }
- };
- }
|