diff options
Diffstat (limited to 'kspread/kspread_functions_statistical.cpp')
-rw-r--r-- | kspread/kspread_functions_statistical.cpp | 1243 |
1 files changed, 1243 insertions, 0 deletions
diff --git a/kspread/kspread_functions_statistical.cpp b/kspread/kspread_functions_statistical.cpp new file mode 100644 index 00000000..26c9d483 --- /dev/null +++ b/kspread/kspread_functions_statistical.cpp @@ -0,0 +1,1243 @@ +/* This file is part of the KDE project + Copyright (C) 1998-2002 The KSpread Team + www.koffice.org/kspread + Copyright (C) 2005 Tomas Mecir <[email protected]> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +// built-in statistical functions + +#include "functions.h" +#include "valuecalc.h" +#include "valueconverter.h" + +// needed for MODE +#include <tqmap.h> + +using namespace KSpread; + +// prototypes (sorted!) +Value func_arrang (valVector args, ValueCalc *calc, FuncExtra *); +Value func_average (valVector args, ValueCalc *calc, FuncExtra *); +Value func_averagea (valVector args, ValueCalc *calc, FuncExtra *); +Value func_avedev (valVector args, ValueCalc *calc, FuncExtra *); +Value func_betadist (valVector args, ValueCalc *calc, FuncExtra *); +Value func_bino (valVector args, ValueCalc *calc, FuncExtra *); +Value func_chidist (valVector args, ValueCalc *calc, FuncExtra *); +Value func_combin (valVector args, ValueCalc *calc, FuncExtra *); +Value func_confidence (valVector args, ValueCalc *calc, FuncExtra *); +Value func_correl_pop (valVector args, ValueCalc *calc, FuncExtra *); +Value func_covar (valVector args, ValueCalc *calc, FuncExtra *); +Value func_devsq (valVector args, ValueCalc *calc, FuncExtra *); +Value func_devsqa (valVector args, ValueCalc *calc, FuncExtra *); +Value func_expondist (valVector args, ValueCalc *calc, FuncExtra *); +Value func_fdist (valVector args, ValueCalc *calc, FuncExtra *); +Value func_fisher (valVector args, ValueCalc *calc, FuncExtra *); +Value func_fisherinv (valVector args, ValueCalc *calc, FuncExtra *); +Value func_gammadist (valVector args, ValueCalc *calc, FuncExtra *); +Value func_gammaln (valVector args, ValueCalc *calc, FuncExtra *); +Value func_gauss (valVector args, ValueCalc *calc, FuncExtra *); +Value func_geomean (valVector args, ValueCalc *calc, FuncExtra *); +Value func_harmean (valVector args, ValueCalc *calc, FuncExtra *); +Value func_hypgeomdist (valVector args, ValueCalc *calc, FuncExtra *); +Value func_kurtosis_est (valVector args, ValueCalc *calc, FuncExtra *); +Value func_kurtosis_pop (valVector args, ValueCalc *calc, FuncExtra *); +Value func_large (valVector args, ValueCalc *calc, FuncExtra *); +Value func_loginv (valVector args, ValueCalc *calc, FuncExtra *); +Value func_lognormdist (valVector args, ValueCalc *calc, FuncExtra *); +Value func_median (valVector args, ValueCalc *calc, FuncExtra *); +Value func_mode (valVector args, ValueCalc *calc, FuncExtra *); +Value func_negbinomdist (valVector args, ValueCalc *calc, FuncExtra *); +Value func_normdist (valVector args, ValueCalc *calc, FuncExtra *); +Value func_norminv (valVector args, ValueCalc *calc, FuncExtra *); +Value func_normsinv (valVector args, ValueCalc *calc, FuncExtra *); +Value func_phi (valVector args, ValueCalc *calc, FuncExtra *); +Value func_poisson (valVector args, ValueCalc *calc, FuncExtra *); +Value func_skew_est (valVector args, ValueCalc *calc, FuncExtra *); +Value func_skew_pop (valVector args, ValueCalc *calc, FuncExtra *); +Value func_small (valVector args, ValueCalc *calc, FuncExtra *); +Value func_standardize (valVector args, ValueCalc *calc, FuncExtra *); +Value func_stddev (valVector args, ValueCalc *calc, FuncExtra *); +Value func_stddeva (valVector args, ValueCalc *calc, FuncExtra *); +Value func_stddevp (valVector args, ValueCalc *calc, FuncExtra *); +Value func_stddevpa (valVector args, ValueCalc *calc, FuncExtra *); +Value func_stdnormdist (valVector args, ValueCalc *calc, FuncExtra *); +Value func_sumproduct (valVector args, ValueCalc *calc, FuncExtra *); +Value func_sumx2py2 (valVector args, ValueCalc *calc, FuncExtra *); +Value func_sumx2my2 (valVector args, ValueCalc *calc, FuncExtra *); +Value func_sumxmy2 (valVector args, ValueCalc *calc, FuncExtra *); +Value func_tdist (valVector args, ValueCalc *calc, FuncExtra *); +Value func_variance (valVector args, ValueCalc *calc, FuncExtra *); +Value func_variancea (valVector args, ValueCalc *calc, FuncExtra *); +Value func_variancep (valVector args, ValueCalc *calc, FuncExtra *); +Value func_variancepa (valVector args, ValueCalc *calc, FuncExtra *); +Value func_weibull (valVector args, ValueCalc *calc, FuncExtra *); + +typedef TQValueList<double> List; + +// registers all statistical functions +void RegisterStatisticalFunctions() +{ + FunctionRepository* repo = FunctionRepository::self(); + Function *f; + + f = new Function ("AVEDEV", func_avedev); + f->setParamCount (1, -1); + f->setAcceptArray (); + repo->add (f); + f = new Function ("AVERAGE", func_average); + f->setParamCount (1, -1); + f->setAcceptArray (); + repo->add (f); + f = new Function ("AVERAGEA", func_averagea); + f->setParamCount (1, -1); + f->setAcceptArray (); + repo->add (f); + f = new Function ("BETADIST", func_betadist); + f->setParamCount (3, 5); + repo->add (f); + f = new Function ("BINO", func_bino); + f->setParamCount (3); + repo->add (f); + f = new Function ("CHIDIST", func_chidist); + f->setParamCount (2); + repo->add (f); + f = new Function ("COMBIN", func_combin); + f->setParamCount (2); + repo->add (f); + f = new Function ("CONFIDENCE", func_confidence); + f->setParamCount (3); + repo->add (f); + f = new Function ("CORREL", func_correl_pop); + f->setParamCount (2); + f->setAcceptArray (); + repo->add (f); + f = new Function ("COVAR", func_covar); + f->setParamCount (2); + f->setAcceptArray (); + repo->add (f); + f = new Function ("DEVSQ", func_devsq); + f->setParamCount (1, -1); + f->setAcceptArray (); + repo->add (f); + f = new Function ("DEVSQA", func_devsqa); + f->setParamCount (1, -1); + f->setAcceptArray (); + repo->add (f); + f = new Function ("EXPONDIST", func_expondist); + f->setParamCount (3); + repo->add (f); + f = new Function ("FDIST", func_fdist); + f->setParamCount (3); + repo->add (f); + f = new Function ("FISHER", func_fisher); + repo->add (f); + f = new Function ("FISHERINV", func_fisherinv); + repo->add (f); + f = new Function ("GAMMADIST", func_gammadist); + f->setParamCount (4); + repo->add (f); + f = new Function ("GAMMALN", func_gammaln); + repo->add (f); + f = new Function ("GAUSS", func_gauss); + repo->add (f); + f = new Function ("GEOMEAN", func_geomean); + f->setParamCount (1, -1); + f->setAcceptArray (); + repo->add (f); + f = new Function ("HARMEAN", func_harmean); + f->setParamCount (1, -1); + f->setAcceptArray (); + repo->add (f); + f = new Function ("HYPGEOMDIST", func_hypgeomdist); + f->setParamCount (4); + repo->add (f); + f = new Function ("INVBINO", func_bino); // same as BINO, for 1.4 compat + repo->add (f); + f = new Function ("KURT", func_kurtosis_est); + f->setParamCount (1, -1); + f->setAcceptArray (); + repo->add (f); + f = new Function ("KURTP", func_kurtosis_pop); + f->setParamCount (1, -1); + f->setAcceptArray (); + repo->add (f); + f = new Function ("LARGE", func_large); + f->setParamCount (2); + f->setAcceptArray (); + repo->add (f); + f = new Function ("LOGINV", func_loginv); + f->setParamCount (3); + repo->add (f); + f = new Function ("LOGNORMDIST", func_lognormdist); + f->setParamCount (3); + repo->add (f); + f = new Function ("MEDIAN", func_median); + f->setParamCount (1, -1); + f->setAcceptArray (); + repo->add (f); + f = new Function ("MODE", func_mode); + f->setParamCount (1, -1); + f->setAcceptArray (); + repo->add (f); + f = new Function ("NEGBINOMDIST", func_negbinomdist); + f->setParamCount (3); + repo->add (f); + f = new Function ("NORMDIST", func_normdist); + f->setParamCount (4); + repo->add (f); + f = new Function ("NORMINV", func_norminv); + f->setParamCount (3); + repo->add (f); + f = new Function ("NORMSDIST", func_stdnormdist); + repo->add (f); + f = new Function ("NORMSINV", func_normsinv); + repo->add (f); + f = new Function ("PEARSON", func_correl_pop); + f->setParamCount (2); + f->setAcceptArray (); + repo->add (f); + f = new Function ("PERMUT", func_arrang); + f->setParamCount (2); + repo->add (f); + f = new Function ("PHI", func_phi); + repo->add (f); + f = new Function ("POISSON", func_poisson); + f->setParamCount (3); + repo->add (f); + f = new Function ("SKEW", func_skew_est); + f->setParamCount (1, -1); + f->setAcceptArray (); + repo->add (f); + f = new Function ("SKEWP", func_skew_pop); + f->setParamCount (1, -1); + f->setAcceptArray (); + repo->add (f); + f = new Function ("SMALL", func_small); + f->setParamCount (2); + f->setAcceptArray (); + repo->add (f); + f = new Function ("STANDARDIZE", func_standardize); + f->setParamCount (3); + repo->add (f); + f = new Function ("STDEV", func_stddev); + f->setParamCount (1, -1); + f->setAcceptArray (); + repo->add (f); + f = new Function ("STDEVA", func_stddeva); + f->setParamCount (1, -1); + f->setAcceptArray (); + repo->add (f); + f = new Function ("STDEVP", func_stddevp); + f->setParamCount (1, -1); + f->setAcceptArray (); + repo->add (f); + f = new Function ("STDEVPA", func_stddevpa); + f->setParamCount (1, -1); + f->setAcceptArray (); + repo->add (f); + f = new Function ("SUM2XMY", func_sumxmy2); + f->setParamCount (2); + f->setAcceptArray (); + repo->add (f); + f = new Function ("SUMPRODUCT", func_sumproduct); + f->setParamCount (2); + f->setAcceptArray (); + repo->add (f); + f = new Function ("SUMX2PY2", func_sumx2py2); + f->setParamCount (2); + f->setAcceptArray (); + repo->add (f); + f = new Function ("SUMX2MY2", func_sumx2my2); + f->setParamCount (2); + f->setAcceptArray (); + repo->add (f); + f = new Function ("TDIST", func_tdist); + f->setParamCount (3); + repo->add (f); + f = new Function ("VARIANCE", func_variance); + f->setParamCount (1, -1); + f->setAcceptArray (); + repo->add (f); + f = new Function ("VAR", func_variance); + f->setParamCount (1, -1); + f->setAcceptArray (); + repo->add (f); + f = new Function ("VARP", func_variancep); + f->setParamCount (1, -1); + f->setAcceptArray (); + repo->add (f); + f = new Function ("VARA", func_variancea); + f->setParamCount (1, -1); + f->setAcceptArray (); + repo->add (f); + f = new Function ("VARPA", func_variancepa); + f->setParamCount (1, -1); + f->setAcceptArray (); + repo->add (f); + f = new Function ("WEIBULL", func_weibull); + f->setParamCount (4); + repo->add (f); +} + +// array-walk functions used in this file + +void awSkew (ValueCalc *c, Value &res, Value val, Value p) +{ + Value avg = p.element (0, 0); + Value stdev = p.element (1, 0); + // (val - avg) / stddev + Value d = c->div (c->sub (val, avg), stdev); + // res += d*d*d + res = c->add (res, c->mul (d, c->mul (d, d))); +} + +void awSumInv (ValueCalc *c, Value &res, Value val, Value) +{ + // res += 1/value + res = c->add (res, c->div (1.0, val)); +} + +void awAveDev (ValueCalc *c, Value &res, Value val, + Value p) +{ + // res += abs (val - p) + res = c->add (res, c->abs (c->sub (val, p))); +} + +void awKurtosis (ValueCalc *c, Value &res, Value val, + Value p) +{ + Value avg = p.element (0, 0); + Value stdev = p.element (1, 0); + //d = (val - avg ) / stdev + Value d = c->div (c->sub (val, avg), stdev); + // res += d^4 + res = c->add (res, c->pow (d, 4)); +} + + +Value func_skew_est (valVector args, ValueCalc *calc, FuncExtra *) +{ + int number = calc->count (args); + Value avg = calc->avg (args); + if (number < 3) + return Value::errorVALUE(); + + Value res = calc->stddev (args, avg); + if (res.isZero()) + return Value::errorVALUE(); + + Value params (2, 1); + params.setElement (0, 0, avg); + params.setElement (1, 0, res); + Value tskew; + calc->arrayWalk (args, tskew, awSkew, params); + + // ((tskew * number) / (number-1)) / (number-2) + return calc->div (calc->div (calc->mul (tskew, number), number-1), number-2); +} + +Value func_skew_pop (valVector args, ValueCalc *calc, FuncExtra *) +{ + int number = calc->count (args); + Value avg = calc->avg (args); + if (number < 1) + return Value::errorVALUE(); + + Value res = calc->stddevP (args, avg); + if (res.isZero()) + return Value::errorVALUE(); + + Value params (2, 1); + params.setElement (0, 0, avg); + params.setElement (1, 0, res); + Value tskew; + calc->arrayWalk (args, tskew, awSkew, params); + + // tskew / number + return calc->div (tskew, number); +} + +class ContentSheet : public TQMap<double, int> {}; + +void func_mode_helper (Value range, ValueCalc *calc, ContentSheet &sh) +{ + if (!range.isArray()) + { + double d = calc->conv()->asFloat (range).asFloat(); + sh[d]++; + return; + } + + for (unsigned int row = 0; row < range.rows(); ++row) + for (unsigned int col = 0; col < range.columns(); ++col) { + Value v = range.element (col, row); + if (v.isArray()) + func_mode_helper (v, calc, sh); + else { + double d = calc->conv()->asFloat (v).asFloat(); + sh[d]++; + } + } +} + +Value func_mode (valVector args, ValueCalc *calc, FuncExtra *) +{ + // does NOT support anything other than doubles !!! + ContentSheet sh; + for (unsigned int i = 0; i < args.count(); ++i) + func_mode_helper (args[i], calc, sh); + + // retrieve value with max.count + int maxcount = 0; + double max = 0.0; + ContentSheet::iterator it; + for (it = sh.begin(); it != sh.end(); ++it) + if (it.data() > maxcount) { + max = it.key(); + maxcount = it.data(); + } + return Value (max); +} + +Value func_covar_helper (Value range1, Value range2, + ValueCalc *calc, Value avg1, Value avg2) +{ + // two arrays -> cannot use arrayWalk + if ((!range1.isArray()) && (!range2.isArray())) + // (v1-E1)*(v2-E2) + return calc->mul (calc->sub (range1, avg1), calc->sub (range2, avg2)); + + int rows = range1.rows(); + int cols = range1.columns(); + int rows2 = range2.rows(); + int cols2 = range2.columns(); + if ((rows != rows2) || (cols != cols2)) + return Value::errorVALUE(); + + Value result = 0.0; + for (int row = 0; row < rows; ++row) + for (int col = 0; col < cols; ++col) { + Value v1 = range1.element (col, row); + Value v2 = range2.element (col, row); + if (v1.isArray() || v2.isArray()) + result = calc->add (result, + func_covar_helper (v1, v2, calc, avg1, avg2)); + else + // result += (v1-E1)*(v2-E2) + result = calc->add (result, calc->mul (calc->sub (v1, avg1), + calc->sub (v2, avg2))); + } + + return result; +} + +Value func_covar (valVector args, ValueCalc *calc, FuncExtra *) +{ + Value avg1 = calc->avg (args[0]); + Value avg2 = calc->avg (args[1]); + int number = calc->count (args[0]); + int number2 = calc->count (args[1]); + + if (number2 <= 0 || number2 != number) + return Value::errorVALUE(); + + Value covar = func_covar_helper (args[0], args[1], calc, avg1, avg2); + return calc->div (covar, number); +} + +Value func_correl_pop (valVector args, ValueCalc *calc, FuncExtra *) +{ + Value covar = func_covar (args, calc, 0); + Value stdevp1 = calc->stddevP (args[0]); + Value stdevp2 = calc->stddevP (args[1]); + + if (calc->isZero (stdevp1) || calc->isZero (stdevp2)) + return Value::errorDIV0(); + + // covar / (stdevp1 * stdevp2) + return calc->div (covar, calc->mul (stdevp1, stdevp2)); +} + +void func_array_helper (Value range, ValueCalc *calc, + List &array, int &number) +{ + if (!range.isArray()) + { + array << calc->conv()->asFloat (range).asFloat(); + ++number; + return; + } + + for (unsigned int row = 0; row < range.rows(); ++row) + for (unsigned int col = 0; col < range.columns(); ++col) { + Value v = range.element (col, row); + if (v.isArray ()) + func_array_helper (v, calc, array, number); + else { + array << calc->conv()->asFloat (v).asFloat(); + ++number; + } + } +} + +Value func_large (valVector args, ValueCalc *calc, FuncExtra *) +{ + // does NOT support anything other than doubles !!! + int k = calc->conv()->asInteger (args[1]).asInteger(); + if ( k < 1 ) + return false; + + List array; + int number = 1; + + func_array_helper (args[0], calc, array, number); + + if ( k > number ) + return Value::errorVALUE(); + + qHeapSort (array); + double d = *array.at (number - k - 1); + return Value (d); +} + +Value func_small (valVector args, ValueCalc *calc, FuncExtra *) +{ + // does NOT support anything other than doubles !!! + int k = calc->conv()->asInteger (args[1]).asInteger(); + if ( k < 1 ) + return false; + + List array; + int number = 1; + + func_array_helper (args[0], calc, array, number); + + if ( k > number ) + return Value::errorVALUE(); + + qHeapSort (array); + double d = *array.at (k - 1); + return Value (d); +} + +Value func_geomean (valVector args, ValueCalc *calc, FuncExtra *) +{ + Value count = calc->count (args); + Value prod = calc->product (args, 1.0); + if (calc->isZero (count)) + return Value::errorDIV0(); + return calc->pow (prod, calc->div (1.0, count)); +} + +Value func_harmean (valVector args, ValueCalc *calc, FuncExtra *) +{ + Value count = calc->count (args); + if (calc->isZero (count)) + return Value::errorDIV0(); + Value suminv; + calc->arrayWalk (args, suminv, awSumInv, 0); + return calc->div (suminv, count); +} + +Value func_loginv (valVector args, ValueCalc *calc, FuncExtra *) +{ + Value p = args[0]; + Value m = args[1]; + Value s = args[2]; + + if (calc->lower (p, 0) || calc->greater (p, 1)) + return Value::errorVALUE(); + + if (!calc->greater (s, 0)) + return Value::errorVALUE(); + + Value result = 0.0; + if (calc->equal (p, 1)) //p==1 + result = Value::errorVALUE(); + else if (calc->greater (p, 0)) { //p>0 + Value gaussInv = calc->gaussinv (p); + // exp (gaussInv * s + m) + result = calc->exp (calc->add (calc->mul (s, gaussInv), m)); + } + + return result; +} + +Value func_devsq (valVector args, ValueCalc *calc, FuncExtra *) +{ + Value res; + calc->arrayWalk (args, res, calc->awFunc ("devsq"), calc->avg (args, false)); + return res; +} + +Value func_devsqa (valVector args, ValueCalc *calc, FuncExtra *) +{ + Value res; + calc->arrayWalk (args, res, calc->awFunc ("devsqa"), calc->avg (args)); + return res; +} + +Value func_kurtosis_est (valVector args, ValueCalc *calc, FuncExtra *) +{ + int count = calc->count (args); + if (count < 4) + return Value::errorVALUE(); + + Value avg = calc->avg (args); + Value devsq; + calc->arrayWalk (args, devsq, calc->awFunc ("devsqa"), avg); + + if (devsq.isZero ()) + return Value::errorDIV0(); + + Value params (2, 1); + params.setElement (0, 0, avg); + params.setElement (1, 0, devsq); + Value x4; + calc->arrayWalk (args, x4, awKurtosis, params); + + double den = (double) (count - 2) * (count - 3); + double nth = (double) count * (count + 1) / ((count - 1) * den); + double t = 3.0 * (count - 1) * (count - 1) / den; + + // res = x4 * nth - t + return calc->sub (calc->mul (x4, nth), t); +} + +Value func_kurtosis_pop (valVector args, ValueCalc *calc, FuncExtra *) +{ + int count = calc->count (args); + if (count < 4) + return Value::errorVALUE(); + + Value avg = calc->avg (args); + Value devsq; + calc->arrayWalk (args, devsq, calc->awFunc ("devsqa"), avg); + + if (devsq.isZero ()) + return Value::errorDIV0(); + + Value params (2, 1); + params.setElement (0, 0, avg); + params.setElement (1, 0, devsq); + Value x4; + calc->arrayWalk (args, x4, awKurtosis, params); + + // x4 / count - 3 + return calc->sub (calc->div (x4, count), 3); +} + +Value func_standardize (valVector args, ValueCalc *calc, FuncExtra *) +{ + Value x = args[0]; + Value m = args[1]; + Value s = args[2]; + + if (!calc->greater (s, 0)) // s must be >0 + return Value::errorVALUE(); + + // (x - m) / s + return calc->div (calc->sub (x, m), s); +} + +Value func_hypgeomdist (valVector args, ValueCalc *calc, FuncExtra *) +{ + int x = calc->conv()->asInteger (args[0]).asInteger(); + int n = calc->conv()->asInteger (args[1]).asInteger(); + int M = calc->conv()->asInteger (args[2]).asInteger(); + int N = calc->conv()->asInteger (args[3]).asInteger(); + + if ( x < 0 || n < 0 || M < 0 || N < 0 ) + return Value::errorVALUE(); + + if ( x > M || n > N ) + return Value::errorVALUE(); + + Value d1 = calc->combin (M, x); + Value d2 = calc->combin (N - M, n - x); + Value d3 = calc->combin (N, n); + + // d1 * d2 / d3 + return calc->div (calc->mul (d1, d2), d3); +} + +Value func_negbinomdist (valVector args, ValueCalc *calc, FuncExtra *) +{ + int x = calc->conv()->asInteger (args[0]).asInteger(); + int r = calc->conv()->asInteger (args[1]).asInteger(); + Value p = args[2]; + + if ((x + r - 1) <= 0) + return Value::errorVALUE(); + if (calc->lower (p, 0) || calc->greater (p, 1)) + return Value::errorVALUE(); + + Value d1 = calc->combin (x + r - 1, r - 1); + // d2 = pow (p, r) * pow (1 - p, x) + Value d2 = calc->mul (calc->pow (p, r), + calc->pow (calc->sub (1, p), x)); + + return calc->mul (d1, d2); +} + +// Function: permut +Value func_arrang (valVector args, ValueCalc *calc, FuncExtra *) +{ + Value n = args[0]; + Value m = args[1]; + if (calc->lower (n, m)) // problem if n<m + return Value::errorVALUE(); + + if (calc->lower (m, 0)) // problem if m<0 (n>=m so that's okay) + return Value::errorVALUE(); + + // fact(n) / (fact(n-m) + return calc->fact (n, calc->sub (n, m)); +} + +// Function: average +Value func_average (valVector args, ValueCalc *calc, FuncExtra *) +{ + return calc->avg (args, false); +} + +// Function: averagea +Value func_averagea (valVector args, ValueCalc *calc, FuncExtra *) +{ + return calc->avg (args); +} + +// Function: avedev +Value func_avedev (valVector args, ValueCalc *calc, FuncExtra *) +{ + Value result; + calc->arrayWalk (args, result, awAveDev, calc->avg (args)); + return result; +} + +// Function: median +Value func_median (valVector args, ValueCalc *calc, FuncExtra *) +{ + // does NOT support anything other than doubles !!! + List array; + int number = 1; + + for (unsigned int i = 0; i < args.count(); ++i) + func_array_helper (args[i], calc, array, number); + + qHeapSort (array); + double d = *array.at (number / 2 + number % 2); + return Value (d); +} + +// Function: variance +Value func_variance (valVector args, ValueCalc *calc, FuncExtra *) +{ + int count = calc->count (args, false); + if (count < 2) + return Value::errorVALUE(); + + Value result = func_devsq (args, calc, 0); + return calc->div (result, count-1); +} + +// Function: vara +Value func_variancea (valVector args, ValueCalc *calc, FuncExtra *) +{ + int count = calc->count (args); + if (count < 2) + return Value::errorVALUE(); + + Value result = func_devsqa (args, calc, 0); + return calc->div (result, count-1); +} + +// Function: varp +Value func_variancep (valVector args, ValueCalc *calc, FuncExtra *) +{ + int count = calc->count (args, false); + if (count == 0) + return Value::errorVALUE(); + + Value result = func_devsq (args, calc, 0); + return calc->div (result, count); +} + +// Function: varpa +Value func_variancepa (valVector args, ValueCalc *calc, FuncExtra *) +{ + int count = calc->count (args); + if (count == 0) + return Value::errorVALUE(); + + Value result = func_devsqa (args, calc, 0); + return calc->div (result, count); +} + +// Function: stddev +Value func_stddev (valVector args, ValueCalc *calc, FuncExtra *) +{ + return calc->stddev (args, false); +} + +// Function: stddeva +Value func_stddeva (valVector args, ValueCalc *calc, FuncExtra *) +{ + return calc->stddev (args); +} + +// Function: stddevp +Value func_stddevp (valVector args, ValueCalc *calc, FuncExtra *) +{ + return calc->stddevP (args, false); +} + +// Function: stddevpa +Value func_stddevpa (valVector args, ValueCalc *calc, FuncExtra *) +{ + return calc->stddevP (args); +} + +// Function: combin +Value func_combin (valVector args, ValueCalc *calc, FuncExtra *) +{ + return calc->combin (args[0], args[1]); +} + +// Function: bino +Value func_bino (valVector args, ValueCalc *calc, FuncExtra *) +{ + Value n = args[0]; + Value m = args[1]; + Value comb = calc->combin (n, m); + Value prob = args[2]; + + if (calc->lower (prob,0) || calc->greater (prob,1)) + return Value::errorVALUE(); + + // result = comb * pow (prob, m) * pow (1 - prob, n - m) + Value pow1 = calc->pow (prob, m); + Value pow2 = calc->pow (calc->sub (1, prob), calc->sub (n, m)); + return calc->mul (comb, calc->mul (pow1, pow2)); +} + +// Function: phi +Value func_phi (valVector args, ValueCalc *calc, FuncExtra *) +//distribution function for a standard normal distribution +{ + return calc->phi (args[0]); +} + +// Function: gauss +Value func_gauss (valVector args, ValueCalc *calc, FuncExtra *) +{ + //returns the integral values of the standard normal cumulative distribution + return calc->gauss (args[0]); +} + +// Function: gammadist +Value func_gammadist (valVector args, ValueCalc *calc, FuncExtra *) +{ + Value x = args[0]; + Value alpha = args[1]; + Value beta = args[2]; + int kum = calc->conv()->asInteger (args[3]).asInteger(); // 0 or 1 + + Value result; + + if (calc->lower (x, 0.0) || (!calc->greater (alpha, 0.0)) || + (!calc->greater (beta, 0.0))) + return Value::errorVALUE(); + + if (kum == 0) { //density + Value G = calc->GetGamma (alpha); + // result = pow (x, alpha - 1.0) / exp (x / beta) / pow (beta, alpha) / G + Value pow1 = calc->pow (x, calc->sub (alpha, 1.0)); + Value pow2 = calc->exp (calc->div (x, beta)); + Value pow3 = calc->pow (beta, alpha); + result = calc->div (calc->div (calc->div (pow1, pow2), pow3), G); + } + else + result = calc->GetGammaDist (x, alpha, beta); + + return Value (result); +} + +// Function: betadist +Value func_betadist (valVector args, ValueCalc *calc, FuncExtra *) +{ + Value x = args[0]; + Value alpha = args[1]; + Value beta = args[2]; + + Value fA = 0.0; + Value fB = 1.0; + if (args.count() > 3) fA = args[3]; + if (args.count() == 5) fB = args[4]; + + //x < fA || x > fB || fA == fB || alpha <= 0.0 || beta <= 0.0 + if (calc->lower (x, fA) || calc->greater (x, fB) || calc->equal (fA, fB) || + (!calc->greater (alpha, 0.0)) || (!calc->greater (beta, 0.0))) + return Value::errorVALUE(); + + // xx = (x - fA) / (fB - fA) // scaling + Value xx = calc->div (calc->sub (x, fA), calc->sub (fB, fA)); + + return calc->GetBeta (xx, alpha, beta); +} + +// Function: fisher +Value func_fisher (valVector args, ValueCalc *calc, FuncExtra *) { + //returns the Fisher transformation for x + + // 0.5 * ln ((1.0 + fVal) / (1.0 - fVal)) + Value fVal = args[0]; + Value num = calc->div (calc->add (fVal, 1.0), calc->sub (1.0, fVal)); + return calc->mul (calc->ln (num), 0.5); +} + +// Function: fisherinv +Value func_fisherinv (valVector args, ValueCalc *calc, FuncExtra *) { + //returns the inverse of the Fisher transformation for x + + Value fVal = args[0]; + // (exp (2.0 * fVal) - 1.0) / (exp (2.0 * fVal) + 1.0) + Value ex = calc->exp (calc->mul (fVal, 2.0)); + return calc->div (calc->sub (ex, 1.0), calc->add (ex, 1.0)); +} + +// Function: normdist +Value func_normdist (valVector args, ValueCalc *calc, FuncExtra *) { + //returns the normal cumulative distribution + Value x = args[0]; + Value mue = args[1]; + Value sigma = args[2]; + Value k = args[3]; + + if (!calc->greater (sigma, 0.0)) + return Value::errorVALUE(); + + // (x - mue) / sigma + Value Y = calc->div (calc->sub (x, mue), sigma); + if (calc->isZero (k)) // density + return calc->div (calc->phi (Y), sigma); + else // distribution + return calc->add (calc->gauss (Y), 0.5); +} + +// Function: lognormdist +Value func_lognormdist (valVector args, ValueCalc *calc, FuncExtra *) { + //returns the cumulative lognormal distribution + Value x = args[0]; + Value mue = args[1]; + Value sigma = args[2]; + + if (!calc->greater (sigma, 0.0) || (!calc->greater (x, 0.0))) + return Value::errorVALUE(); + + // (ln(x) - mue) / sigma + Value Y = calc->div (calc->sub (calc->ln (x), mue), sigma); + return calc->add (calc->gauss (Y), 0.5); +} + +// Function: normsdist +Value func_stdnormdist (valVector args, ValueCalc *calc, FuncExtra *) +{ + //returns the cumulative lognormal distribution, mue=0, sigma=1 + return calc->add (calc->gauss (args[0]), 0.5); +} + +// Function: expondist +Value func_expondist (valVector args, ValueCalc *calc, FuncExtra *) { + //returns the exponential distribution + Value x = args[0]; + Value lambda = args[1]; + Value kum = args[2]; + + Value result = 0.0; + + if (!calc->greater (lambda, 0.0)) + return Value::errorVALUE(); + + // ex = exp (-lambda * x) + Value ex = calc->exp (calc->mul (calc->mul (lambda, -1), x)); + if (calc->isZero (kum)) { //density + if (!calc->lower (x, 0.0)) + // lambda * ex + result = calc->mul (lambda, ex); + } + else { //distribution + if (calc->greater (x, 0.0)) + // 1.0 - ex + result = calc->sub (1.0, ex); + } + return result; +} + +// Function: weibull +Value func_weibull (valVector args, ValueCalc *calc, FuncExtra *) { + //returns the Weibull distribution + + Value x = args[0]; + Value alpha = args[1]; + Value beta = args[2]; + Value kum = args[3]; + + Value result; + + if ((!calc->greater (alpha, 0.0)) || (!calc->greater (beta, 0.0)) || + calc->lower (x, 0.0)) + return Value::errorVALUE(); + + // ex = exp (-pow (x / beta, alpha)) + Value ex; + ex = calc->exp (calc->mul (calc->pow (calc->div (x, beta), alpha), -1)); + if (calc->isZero (kum)) // density + { + // result = alpha / pow(beta,alpha) * pow(x,alpha-1.0) * ex + result = calc->div (alpha, calc->pow (beta, alpha)); + result = calc->mul (result, calc->mul (calc->pow (x, + calc->sub (alpha, 1)), ex)); + } + else // distribution + result = calc->sub (1.0, ex); + + return result; +} + +// Function: normsinv +Value func_normsinv (valVector args, ValueCalc *calc, FuncExtra *) { + //returns the inverse of the standard normal cumulative distribution + + Value x = args[0]; + if (!(calc->greater (x, 0.0) && calc->lower (x, 1.0))) + return Value::errorVALUE(); + + return calc->gaussinv (x); +} + +// Function: norminv +Value func_norminv (valVector args, ValueCalc *calc, FuncExtra *) { + //returns the inverse of the normal cumulative distribution + Value x = args[0]; + Value mue = args[1]; + Value sigma = args[2]; + + if (!calc->greater (sigma, 0.0)) + return Value::errorVALUE(); + if (!(calc->greater (x, 0.0) && calc->lower (x, 1.0))) + return Value::errorVALUE(); + + // gaussinv (x)*sigma + mue + return calc->add (calc->mul (calc->gaussinv (x), sigma), mue); +} + +// Function: gammaln +Value func_gammaln (valVector args, ValueCalc *calc, FuncExtra *) { + //returns the natural logarithm of the gamma function + + if (calc->greater (args[0], 0.0)) + return calc->GetLogGamma (args[0]); + return Value::errorVALUE(); +} + +// Function: poisson +Value func_poisson (valVector args, ValueCalc *calc, FuncExtra *) { + //returns the Poisson distribution + + Value x = args[0]; + Value lambda = args[1]; + Value kum = args[2]; + + // lambda < 0.0 || x < 0.0 + if (calc->lower (lambda, 0.0) || calc->lower (x, 0.0)) + return Value::errorVALUE(); + + Value result; + + // ex = exp (-lambda) + Value ex = calc->exp (calc->mul (lambda, -1)); + + if (calc->isZero (kum)) { // density + if (calc->isZero (lambda)) + result = 0; + else + // ex * pow (lambda, x) / fact (x) + result = calc->div (calc->mul (ex, calc->pow (lambda, x)), calc->fact (x)); + } + else { // distribution + if (calc->isZero (lambda)) + result = 1; + else + { + result = 1.0; + Value fFak = 1.0; + unsigned long nEnd = calc->conv()->asInteger (x).asInteger(); + for (unsigned long i = 1; i <= nEnd; i++) + { + // fFak *= i + fFak = calc->mul (fFak, i); + // result += pow (lambda, i) / fFak + result = calc->add (result, calc->div (calc->pow (lambda, i), fFak)); + } + result = calc->mul (result, ex); + } + } + + return result; +} + +// Function: confidence +Value func_confidence (valVector args, ValueCalc *calc, FuncExtra *) { + //returns the confidence interval for a population mean + Value alpha = args[0]; + Value sigma = args[1]; + Value n = args[2]; + + // sigma <= 0.0 || alpha <= 0.0 || alpha >= 1.0 || n < 1 + if ((!calc->greater (sigma, 0.0)) || (!calc->greater (alpha, 0.0)) || + (!calc->lower (alpha, 1.0)) || calc->lower (n, 1)) + return Value::errorVALUE(); + + // g = gaussinv (1.0 - alpha / 2.0) + Value g = calc->gaussinv (calc->sub (1.0, calc->div (alpha, 2.0))); + // g * sigma / sqrt (n) + return calc->div (calc->mul (g, sigma), calc->sqrt (n)); +} + +// Function: tdist +Value func_tdist (valVector args, ValueCalc *calc, FuncExtra *) { + //returns the t-distribution + + Value T = args[0]; + Value fDF = args[1]; + int flag = calc->conv()->asInteger (args[2]).asInteger(); + + if (calc->lower (fDF, 1) || calc->lower (T, 0.0) || (flag != 1 && flag != 2)) + return Value::errorVALUE(); + + // arg = fDF / (fDF + T * T) + Value arg = calc->div (fDF, calc->add (fDF, calc->sqr (T))); + + Value R; + R = calc->mul (calc->GetBeta (arg, calc->div (fDF, 2.0), 0.5), 0.5); + + if (flag == 1) + return R; + return calc->mul (R, 2); // flag is 2 here +} + +// Function: fdist +Value func_fdist (valVector args, ValueCalc *calc, FuncExtra *) { + //returns the f-distribution + + Value x = args[0]; + Value fF1 = args[1]; + Value fF2 = args[2]; + + // x < 0.0 || fF1 < 1 || fF2 < 1 || fF1 >= 1.0E10 || fF2 >= 1.0E10 + if (calc->lower (x, 0.0) || calc->lower (fF1, 1) || calc->lower (fF2, 1) || + (!calc->lower (fF1, 1.0E10)) || (!calc->lower (fF2, 1.0E10))) + return Value::errorVALUE(); + + // arg = fF2 / (fF2 + fF1 * x) + Value arg = calc->div (fF2, calc->add (fF2, calc->mul (fF1, x))); + // alpha = fF2/2.0 + Value alpha = calc->div (fF2, 2.0); + // beta = fF1/2.0 + Value beta = calc->div (fF1, 2.0); + return calc->GetBeta (arg, alpha, beta); +} + +// Function: chidist +Value func_chidist (valVector args, ValueCalc *calc, FuncExtra *) { + //returns the chi-distribution + + Value fChi = args[0]; + Value fDF = args[1]; + + // fDF < 1 || fDF >= 1.0E5 || fChi < 0.0 + if (calc->lower (fDF, 1) || (!calc->lower (fDF, 1.0E5)) || + calc->lower (fChi, 0.0)) + return Value::errorVALUE(); + + // 1.0 - GetGammaDist (fChi / 2.0, fDF / 2.0, 1.0) + return calc->sub (1.0, calc->GetGammaDist (calc->div (fChi, 2.0), + calc->div (fDF, 2.0), 1.0)); +} + + +// two-array-walk functions used in the two-sum functions + +void tawSumproduct (ValueCalc *c, Value &res, Value v1, + Value v2) { + // res += v1*v2 + res = c->add (res, c->mul (v1, v2)); +} + +void tawSumx2py2 (ValueCalc *c, Value &res, Value v1, + Value v2) { + // res += sqr(v1)+sqr(v2) + res = c->add (res, c->add (c->sqr (v1), c->sqr (v2))); +} + +void tawSumx2my2 (ValueCalc *c, Value &res, Value v1, + Value v2) { + // res += sqr(v1)-sqr(v2) + res = c->add (res, c->sub (c->sqr (v1), c->sqr (v2))); +} + +void tawSumxmy2 (ValueCalc *c, Value &res, Value v1, + Value v2) { + // res += sqr(v1-v2) + res = c->add (res, c->sqr (c->sub (v1, v2))); + +} + +// Function: sumproduct +Value func_sumproduct (valVector args, ValueCalc *calc, FuncExtra *) +{ + Value result; + calc->twoArrayWalk (args[0], args[1], result, tawSumproduct); + return result; +} + +// Function: sumx2py2 +Value func_sumx2py2 (valVector args, ValueCalc *calc, FuncExtra *) +{ + Value result; + calc->twoArrayWalk (args[0], args[1], result, tawSumx2py2); + return result; +} + +// Function: sumx2my2 +Value func_sumx2my2 (valVector args, ValueCalc *calc, FuncExtra *) +{ + Value result; + calc->twoArrayWalk (args[0], args[1], result, tawSumx2my2); + return result; +} + +// Function: sum2xmy +Value func_sumxmy2 (valVector args, ValueCalc *calc, FuncExtra *) +{ + Value result; + calc->twoArrayWalk (args[0], args[1], result, tawSumxmy2); + return result; +} |