/* This file is part of the KDE project Copyright (C) 1998-2002 The KSpread Team www.koffice.org/kspread Copyright (C) 2005 Tomas Mecir 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 math functions #include #include #include "functions.h" #include "valuecalc.h" #include "valueconverter.h" // these two are needed for SUBTOTAL: #include "kspread_cell.h" #include "kspread_sheet.h" // needed for RANDBINOM and so #include using namespace KSpread; // RANDBINOM and RANDNEGBINOM won't support arbitrary precision // prototypes Value func_abs (valVector args, ValueCalc *calc, FuncExtra *); Value func_ceil (valVector args, ValueCalc *calc, FuncExtra *); Value func_ceiling (valVector args, ValueCalc *calc, FuncExtra *); Value func_count (valVector args, ValueCalc *calc, FuncExtra *); Value func_counta (valVector args, ValueCalc *calc, FuncExtra *); Value func_countblank (valVector args, ValueCalc *calc, FuncExtra *); Value func_countif (valVector args, ValueCalc *calc, FuncExtra *); Value func_cur (valVector args, ValueCalc *calc, FuncExtra *); Value func_div (valVector args, ValueCalc *calc, FuncExtra *); Value func_eps (valVector args, ValueCalc *calc, FuncExtra *); Value func_even (valVector args, ValueCalc *calc, FuncExtra *); Value func_exp (valVector args, ValueCalc *calc, FuncExtra *); Value func_fact (valVector args, ValueCalc *calc, FuncExtra *); Value func_factdouble (valVector args, ValueCalc *calc, FuncExtra *); Value func_fib (valVector args, ValueCalc *calc, FuncExtra *); Value func_floor (valVector args, ValueCalc *calc, FuncExtra *); Value func_gcd (valVector args, ValueCalc *calc, FuncExtra *); Value func_int (valVector args, ValueCalc *calc, FuncExtra *); Value func_inv (valVector args, ValueCalc *calc, FuncExtra *); Value func_kproduct (valVector args, ValueCalc *calc, FuncExtra *); Value func_lcm (valVector args, ValueCalc *calc, FuncExtra *); Value func_ln (valVector args, ValueCalc *calc, FuncExtra *); Value func_log2 (valVector args, ValueCalc *calc, FuncExtra *); Value func_log10 (valVector args, ValueCalc *calc, FuncExtra *); Value func_logn (valVector args, ValueCalc *calc, FuncExtra *); Value func_max (valVector args, ValueCalc *calc, FuncExtra *); Value func_maxa (valVector args, ValueCalc *calc, FuncExtra *); Value func_mdeterm (valVector args, ValueCalc *calc, FuncExtra *); Value func_min (valVector args, ValueCalc *calc, FuncExtra *); Value func_mina (valVector args, ValueCalc *calc, FuncExtra *); Value func_mmult (valVector args, ValueCalc *calc, FuncExtra *); Value func_mod (valVector args, ValueCalc *calc, FuncExtra *); Value func_mround (valVector args, ValueCalc *calc, FuncExtra *); Value func_mult (valVector args, ValueCalc *calc, FuncExtra *); Value func_multinomial (valVector args, ValueCalc *calc, FuncExtra *); Value func_odd (valVector args, ValueCalc *calc, FuncExtra *); Value func_pow (valVector args, ValueCalc *calc, FuncExtra *); Value func_quotient (valVector args, ValueCalc *calc, FuncExtra *); Value func_product (valVector args, ValueCalc *calc, FuncExtra *); Value func_rand (valVector args, ValueCalc *calc, FuncExtra *); Value func_randbetween (valVector args, ValueCalc *calc, FuncExtra *); Value func_randbernoulli (valVector args, ValueCalc *calc, FuncExtra *); Value func_randbinom (valVector args, ValueCalc *calc, FuncExtra *); Value func_randexp (valVector args, ValueCalc *calc, FuncExtra *); Value func_randnegbinom (valVector args, ValueCalc *calc, FuncExtra *); Value func_randnorm (valVector args, ValueCalc *calc, FuncExtra *); Value func_randpoisson (valVector args, ValueCalc *calc, FuncExtra *); Value func_rootn (valVector args, ValueCalc *calc, FuncExtra *); Value func_round (valVector args, ValueCalc *calc, FuncExtra *); Value func_rounddown (valVector args, ValueCalc *calc, FuncExtra *); Value func_roundup (valVector args, ValueCalc *calc, FuncExtra *); Value func_sign (valVector args, ValueCalc *calc, FuncExtra *); Value func_sqrt (valVector args, ValueCalc *calc, FuncExtra *); Value func_sqrtpi (valVector args, ValueCalc *calc, FuncExtra *); Value func_subtotal (valVector args, ValueCalc *calc, FuncExtra *); Value func_sum (valVector args, ValueCalc *calc, FuncExtra *); Value func_suma (valVector args, ValueCalc *calc, FuncExtra *); Value func_sumif (valVector args, ValueCalc *calc, FuncExtra *); Value func_sumsq (valVector args, ValueCalc *calc, FuncExtra *); Value func_trunc (valVector args, ValueCalc *calc, FuncExtra *); // Value func_multipleOP (valVector args, ValueCalc *calc, FuncExtra *); // registers all math functions void RegisterMathFunctions() { FunctionRepository* repo = FunctionRepository::self(); Function *f; /* f = new Function ("MULTIPLEOPERATIONS", func_multipleOP); repo->add (f); */ // functions that don't take array parameters f = new Function ("ABS", func_abs); repo->add (f); f = new Function ("CEIL", func_ceil); repo->add (f); f = new Function ("CEILING", func_ceiling); f->setParamCount (1, 2); repo->add (f); f = new Function ("CUR", func_cur); repo->add (f); f = new Function ("EPS", func_eps); f->setParamCount (0); repo->add (f); f = new Function ("EVEN", func_even); repo->add (f); f = new Function ("EXP", func_exp); repo->add (f); f = new Function ("FACT", func_fact); repo->add (f); f = new Function ("FACTDOUBLE", func_factdouble); repo->add (f); f = new Function ("FIB", func_fib); // KSpread-specific, like Quattro-Pro's FIB repo->add (f); f = new Function ("FLOOR", func_floor); repo->add (f); f = new Function ("INT", func_int); repo->add (f); f = new Function ("INV", func_inv); repo->add (f); f = new Function ("LN", func_ln); repo->add (f); f = new Function ("LOG", func_log10); repo->add (f); f = new Function ("LOG2", func_log2); repo->add (f); f = new Function ("LOG10", func_log10); // same as LOG repo->add (f); f = new Function ("LOGN", func_logn); f->setParamCount (2); repo->add (f); f = new Function ("MOD", func_mod); f->setParamCount (2); repo->add (f); f = new Function ("MROUND", func_mround); f->setParamCount (2); repo->add (f); f = new Function ("MULTINOMIAL", func_multinomial); f->setParamCount (1, -1); repo->add (f); f = new Function ("ODD", func_odd); repo->add (f); f = new Function ("POW", func_pow); f->setParamCount (2); repo->add (f); f = new Function ("POWER", func_pow); f->setParamCount (2); repo->add (f); f = new Function ("TQUOTIENT", func_quotient); f->setParamCount (2); repo->add (f); f = new Function ("RAND", func_rand); f->setParamCount (0); repo->add (f); f = new Function ("RANDBERNOULLI", func_randbernoulli); repo->add (f); f = new Function ("RANDBETWEEN", func_randbetween); f->setParamCount (2); repo->add (f); f = new Function ("RANDBINOM", func_randbinom); f->setParamCount (2); repo->add (f); f = new Function ("RANDEXP", func_randexp); repo->add (f); f = new Function ("RANDNEGBINOM", func_randnegbinom); f->setParamCount (2); repo->add (f); f = new Function ("RANDNORM", func_randnorm); f->setParamCount (2); repo->add (f); f = new Function ("RANDPOISSON", func_randpoisson); repo->add (f); f = new Function ("ROOTN", func_rootn); f->setParamCount (2); repo->add (f); f = new Function ("ROUND", func_round); f->setParamCount (1, 2); repo->add (f); f = new Function ("ROUNDDOWN", func_rounddown); f->setParamCount (1, 2); repo->add (f); f = new Function ("ROUNDUP", func_roundup); f->setParamCount (1, 2); repo->add (f); f = new Function ("SIGN", func_sign); repo->add (f); f = new Function ("SQRT", func_sqrt); repo->add (f); f = new Function ("SQRTPI", func_sqrtpi); repo->add (f); f = new Function ("TRUNC", func_trunc); f->setParamCount (1, 2); repo->add (f); // functions that operate over arrays f = new Function ("COUNT", func_count); f->setParamCount (1, -1); f->setAcceptArray (); repo->add (f); f = new Function ("COUNTA", func_counta); f->setParamCount (1, -1); f->setAcceptArray (); repo->add (f); f = new Function ("COUNTBLANK", func_countblank); f->setParamCount (1, -1); f->setAcceptArray (); repo->add (f); f = new Function ("COUNTIF", func_countif); f->setParamCount (2); f->setAcceptArray (); repo->add (f); f = new Function ("DIV", func_div); f->setParamCount (1, -1); f->setAcceptArray (); repo->add (f); f = new Function ("G_PRODUCT", func_kproduct); // Gnumeric compatibility f->setParamCount (1, -1); f->setAcceptArray (); repo->add (f); f = new Function ("GCD", func_gcd); f->setParamCount (1, -1); f->setAcceptArray (); repo->add (f); f = new Function ("KPRODUCT", func_kproduct); f->setParamCount (1, -1); f->setAcceptArray (); repo->add (f); f = new Function ("LCM", func_lcm); f->setParamCount (1, -1); f->setAcceptArray (); repo->add (f); f = new Function ("MAX", func_max); f->setParamCount (1, -1); f->setAcceptArray (); repo->add (f); f = new Function ("MAXA", func_maxa); f->setParamCount (1, -1); f->setAcceptArray (); repo->add (f); f = new Function ("MDETERM", func_mdeterm); f->setParamCount (1); f->setAcceptArray (); repo->add (f); f = new Function ("MIN", func_min); f->setParamCount (1, -1); f->setAcceptArray (); repo->add (f); f = new Function ("MINA", func_mina); f->setParamCount (1, -1); f->setAcceptArray (); repo->add (f); f = new Function ("MMULT", func_mmult); f->setParamCount (2); f->setAcceptArray (); repo->add (f); f = new Function ("MULTIPLY", func_product); // same as PRODUCT f->setParamCount (1, -1); f->setAcceptArray (); repo->add (f); f = new Function ("PRODUCT", func_product); f->setParamCount (1, -1); f->setAcceptArray (); repo->add (f); f = new Function ("SUM", func_sum); f->setParamCount (1, -1); f->setAcceptArray (); repo->add (f); f = new Function ("SUMA", func_suma); f->setParamCount (1, -1); f->setAcceptArray (); repo->add (f); f = new Function ("SUBTOTAL", func_subtotal); f->setParamCount (2); f->setAcceptArray (); f->setNeedsExtra (true); repo->add (f); f = new Function ("SUMIF", func_sumif); f->setParamCount (2, 3); f->setAcceptArray (); repo->add (f); f = new Function ("SUMSQ", func_sumsq); f->setParamCount (1, -1); f->setAcceptArray (); repo->add (f); } // Function: SQRT Value func_sqrt (valVector args, ValueCalc *calc, FuncExtra *) { return calc->sqrt (args[0]); } // Function: SQRTPI Value func_sqrtpi (valVector args, ValueCalc *calc, FuncExtra *) { // sqrt (val * PI) return calc->sqrt (calc->mul (args[0], calc->pi())); } // Function: ROOTN Value func_rootn (valVector args, ValueCalc *calc, FuncExtra *) { return calc->pow (args[0], calc->div (1, args[1])); } // Function: CUR Value func_cur (valVector args, ValueCalc *calc, FuncExtra *) { return calc->pow (args[0], 1.0/3.0); } // Function: ABS Value func_abs (valVector args, ValueCalc *calc, FuncExtra *) { return calc->abs (args[0]); } // Function: exp Value func_exp (valVector args, ValueCalc *calc, FuncExtra *) { return calc->exp (args[0]); } // Function: ceil Value func_ceil (valVector args, ValueCalc *calc, FuncExtra *) { return calc->roundUp (args[0], 0); } // Function: ceiling Value func_ceiling (valVector args, ValueCalc *calc, FuncExtra *) { Value number = args[0]; Value res; if (args.count() == 2) res = args[1]; else res = calc->gequal (number, 0.0) ? 1.0 : -1.0; if (calc->isZero(res)) return Value::errorDIV0(); Value d = calc->div (number, res); if (calc->greater (0, d)) return Value::errorVALUE(); Value rud = calc->roundDown (d); if (calc->approxEqual (rud, d)) d = calc->mul (rud, res); else d = calc->mul (calc->roundUp (d), res); return d; } // Function: floor Value func_floor (valVector args, ValueCalc *calc, FuncExtra *) { return calc->roundDown (args[0], 0); } // Function: ln Value func_ln (valVector args, ValueCalc *calc, FuncExtra *) { return calc->ln (args[0]); } // Function: LOGn Value func_logn (valVector args, ValueCalc *calc, FuncExtra *) { return calc->log (args[0], args[1]); } // Function: LOG2 Value func_log2 (valVector args, ValueCalc *calc, FuncExtra *) { return calc->log (args[0], 2.0); } // Function: LOG10 Value func_log10 (valVector args, ValueCalc *calc, FuncExtra *) { return calc->log (args[0]); } // Function: sum Value func_sum (valVector args, ValueCalc *calc, FuncExtra *) { return calc->sum (args, false); } // Function: suma Value func_suma (valVector args, ValueCalc *calc, FuncExtra *) { return calc->sum (args, true); } Value func_sumif (valVector args, ValueCalc *calc, FuncExtra *) { Value checkRange = args[0]; TQString condition = calc->conv()->asString (args[1]).asString(); Value sumRange = checkRange; if (args.count() == 3) sumRange = args[2]; Condition cond; calc->getCond (cond, condition); return calc->sumIf (sumRange, checkRange, cond); } // Function: product Value func_product (valVector args, ValueCalc *calc, FuncExtra *) { return calc->product (args, 0.0); } // Function: kproduct Value func_kproduct (valVector args, ValueCalc *calc, FuncExtra *) { return calc->product (args, 1.0); } // Function: DIV Value func_div (valVector args, ValueCalc *calc, FuncExtra *) { Value val = args[0]; for (unsigned int i = 1; i < args.count(); ++i) { val = calc->div (val, args[i]); if (val.isError()) return val; } return val; } // Function: SUMSQ Value func_sumsq (valVector args, ValueCalc *calc, FuncExtra *) { Value res; calc->arrayWalk (args, res, calc->awFunc ("sumsq"), 0); return res; } // Function: MAX Value func_max (valVector args, ValueCalc *calc, FuncExtra *) { Value m = calc->max (args, false); return m.isEmpty() ? Value(0.0) : m; } // Function: MAXA Value func_maxa (valVector args, ValueCalc *calc, FuncExtra *) { Value m = calc->max (args); return m.isEmpty() ? Value(0.0) : m; } // Function: MIN Value func_min (valVector args, ValueCalc *calc, FuncExtra *) { Value m = calc->min (args, false); return m.isEmpty() ? Value(0.0) : m; } // Function: MINA Value func_mina (valVector args, ValueCalc *calc, FuncExtra *) { Value m = calc->min (args); return m.isEmpty() ? Value(0.0) : m; } // Function: INT Value func_int (valVector args, ValueCalc *calc, FuncExtra *) { return calc->conv()->asInteger (args[0]); } // Function: TQUOTIENT Value func_quotient (valVector args, ValueCalc *calc, FuncExtra *) { if (calc->isZero (args[1])) return Value::errorDIV0(); return calc->conv()->asInteger (calc->div (args[0], args[1])); } // Function: eps Value func_eps (valVector, ValueCalc *calc, FuncExtra *) { return calc->eps (); } Value func_randexp (valVector args, ValueCalc *calc, FuncExtra *) { // -1 * d * log (random) return calc->mul (calc->mul (args[0], -1), calc->random()); } Value func_randbinom (valVector args, ValueCalc *calc, FuncExtra *) { // this function will not support arbitrary precision double d = calc->conv()->asFloat (args[0]).asFloat(); int tr = calc->conv()->asInteger (args[1]).asInteger(); if ( d < 0 || d > 1 ) return Value::errorVALUE(); if ( tr < 0 ) return Value::errorVALUE(); // taken from gnumeric double x = pow(1 - d, tr); double r = (double) rand() / ( RAND_MAX + 1.0 ); double t = x; int i = 0; while (r > t) { x *= (((tr - i) * d) / ((1 + i) * (1 - d))); i++; t += x; } return Value (i); } Value func_randnegbinom (valVector args, ValueCalc *calc, FuncExtra *) { // this function will not support arbitrary precision double d = calc->conv()->asFloat (args[0]).asFloat(); int f = calc->conv()->asInteger (args[1]).asInteger(); if ( d < 0 || d > 1 ) return Value::errorVALUE(); if ( f < 0 ) return Value::errorVALUE(); // taken from Gnumeric double x = pow(d, f); double r = (double) rand() / ( RAND_MAX + 1.0 ); double t = x; int i = 0; while (r > t) { x *= ( ( ( f + i ) * ( 1 - d ) ) / (1 + i) ) ; i++; t += x; } return Value (i); } Value func_randbernoulli (valVector args, ValueCalc *calc, FuncExtra *) { Value rnd = calc->random (); return Value (calc->greater (rnd, args[0]) ? 1.0 : 0.0); } Value func_randnorm (valVector args, ValueCalc *calc, FuncExtra *) { Value mu = args[0]; Value sigma = args[1]; //using polar form of the Box-Muller transformation //refer to http://www.taygeta.com/random/gaussian.html for more info Value x1, x2, w; do { // x1,x2 = 2 * random() - 1 x1 = calc->random (2.0); x2 = calc->random (2.0); x1 = calc->sub (x1, 1); x1 = calc->sub (x2, 1); w = calc->add (calc->sqr(x1), calc->sqr (x2)); } while (calc->gequal (w, 1.0)); // w >= 1.0 //sqrt ((-2.0 * log (w)) / w) : w = calc->sqrt (calc->div (calc->mul (-2.0, calc->ln (w)), w)); Value res = calc->mul (x1, w); res = calc->add (calc->mul (res, sigma), mu); // res*sigma + mu return res; } Value func_randpoisson (valVector args, ValueCalc *calc, FuncExtra *) { if (calc->lower (args[0], 0)) return Value::errorVALUE(); // taken from Gnumeric... Value x = calc->exp (calc->mul (-1, args[0])); // e^(-A) Value r = calc->random (); Value t = x; int i = 0; while (calc->greater (r, t)) { // r > t x = calc->mul (x, calc->div (args[0], i + 1)); // x *= (A/(i+1)) t = calc->add (t, x); //t += x i++; } return Value (i); } // Function: rand Value func_rand (valVector, ValueCalc *calc, FuncExtra *) { return calc->random (); } // Function: RANDBETWEEN Value func_randbetween (valVector args, ValueCalc *calc, FuncExtra *) { Value v1 = args[0]; Value v2 = args[1]; if (calc->greater (v2, v1)) { v1 = args[1]; v2 = args[0]; } return calc->add (v1, calc->random (calc->sub (v2, v1))); } // Function: POW Value func_pow (valVector args, ValueCalc *calc, FuncExtra *) { return calc->pow (args[0], args[1]); } // Function: MOD Value func_mod (valVector args, ValueCalc *calc, FuncExtra *) { return calc->mod (args[0], args[1]); } // Function: fact Value func_fact (valVector args, ValueCalc *calc, FuncExtra *) { return calc->fact (args[0]); } // Function: FACTDOUBLE Value func_factdouble (valVector args, ValueCalc *calc, FuncExtra *) { return calc->factDouble (args[0]); } // Function: MULTINOMIAL Value func_multinomial (valVector args, ValueCalc *calc, FuncExtra *) { // (a+b+c)! / a!b!c! (any number of params possible) Value num = 0, den = 1; for (unsigned int i = 0; i < args.count(); ++i) { num = calc->add (num, args[i]); den = calc->mul (den, calc->fact (args[i])); } num = calc->fact (num); return calc->div (num, den); } // Function: sign Value func_sign (valVector args, ValueCalc *calc, FuncExtra *) { return Value (calc->sign (args[0])); } // Function: INV Value func_inv (valVector args, ValueCalc *calc, FuncExtra *) { return calc->mul (args[0], -1); } Value func_mround (valVector args, ValueCalc *calc, FuncExtra *) { Value d = args[0]; Value m = args[1]; // signs must be the same if ((calc->greater (d, 0) && calc->lower (m, 0)) || (calc->lower (d, 0) && calc->greater (m, 0))) return Value::errorVALUE(); int sign = 1; if (calc->lower (d, 0)) { sign = -1; d = calc->mul (d, -1); m = calc->mul (m, -1); } // from gnumeric: Value mod = calc->mod (d, m); Value div = calc->sub (d, mod); Value result = div; if (calc->greater (mod, calc->div (m, 2))) // mod > m/2 result = calc->add (result, m); // result += m result = calc->mul (result, sign); // add the sign return result; } // Function: ROUNDDOWN Value func_rounddown (valVector args, ValueCalc *calc, FuncExtra *) { if (args.count() == 2) return calc->roundDown (args[0], args[1]); return calc->roundDown (args[0], 0); } // Function: ROUNDUP Value func_roundup (valVector args, ValueCalc *calc, FuncExtra *) { if (args.count() == 2) return calc->roundUp (args[0], args[1]); return calc->roundUp (args[0], 0); } // Function: ROUND Value func_round (valVector args, ValueCalc *calc, FuncExtra *) { if (args.count() == 2) return calc->round (args[0], args[1]); return calc->round (args[0], 0); } // Function: EVEN Value func_even (valVector args, ValueCalc *calc, FuncExtra *) { const Value value = calc->roundUp (args[0], 0); return calc->isZero( calc->mod(value, 2) ) ? value : calc->add(value, 1); } // Function: ODD Value func_odd (valVector args, ValueCalc *calc, FuncExtra *) { const Value value = calc->roundUp (args[0], 0); return calc->isZero( calc->mod(value, 2) ) ? calc->add(value, 1) : value; } Value func_trunc (valVector args, ValueCalc *calc, FuncExtra *) { if (args.count() == 1) return calc->roundDown (args[0]); return calc->roundDown (args[0], args[1]); } // Function: COUNT Value func_count (valVector args, ValueCalc *calc, FuncExtra *) { return calc->count (args, false); } // Function: COUNTA Value func_counta (valVector args, ValueCalc *calc, FuncExtra *) { return calc->count (args); } // Function: COUNTBLANK Value func_countblank (valVector args, ValueCalc *, FuncExtra *) { int cnt = 0; for (unsigned int i = 0; i < args.count(); ++i) if (args[i].isArray()) { int rows = args[i].rows(); int cols = args[i].columns(); for (int r = 0; r < rows; ++r) for (int c = 0; c < cols; ++c) if (args[i].element (c, r).isEmpty()) cnt++; } else if (args[i].isEmpty()) cnt++; return Value (cnt); } // Function: COUNTIF Value func_countif (valVector args, ValueCalc *calc, FuncExtra *) { Value range = args[0]; TQString condition = calc->conv()->asString (args[1]).asString(); Condition cond; calc->getCond (cond, condition); return calc->countIf (range, cond); } // Function: FIB Value func_fib (valVector args, ValueCalc *calc, FuncExtra *) { /* Lucas' formula for the nth Fibonacci number F(n) is given by ((1+sqrt(5))/2)^n - ((1-sqrt(5))/2)^n F(n) = ------------------------------------- . sqrt(5) */ Value n = args[0]; Value s = calc->sqrt (5.0); // u1 = ((1+sqrt(5))/2)^n Value u1 = calc->pow (calc->div (calc->add (1, s), 2), n); // u2 = ((1-sqrt(5))/2)^n Value u2 = calc->pow (calc->div (calc->sub (1, s), 2), n); Value result = calc->div (calc->sub (u1, u2), s); return result; } static Value func_gcd_helper(const Value &val, ValueCalc *calc) { Value res = 0; if (!val.isArray ()) return val; for (unsigned int row = 0; row < val.rows(); ++row) for (unsigned int col = 0; col < val.columns(); ++col) { Value v = val.element (col, row); if (v.isArray ()) v = func_gcd_helper (v, calc); res = calc->gcd (res, v); } return res; } // Function: GCD Value func_gcd (valVector args, ValueCalc *calc, FuncExtra *) { Value result = 0; for (unsigned int i = 0; i < args.count(); ++i) if (args[i].isArray()) result = calc->gcd (result, func_gcd_helper (args[i], calc)); else result = calc->gcd (result, args[i]); return result; } static Value func_lcm_helper(const Value &val, ValueCalc *calc) { Value res = 0; if (!val.isArray ()) return val; for (unsigned int row = 0; row < val.rows(); ++row) for (unsigned int col = 0; col < val.columns(); ++col) { Value v = val.element (col, row); if (v.isArray ()) v = func_lcm_helper (v, calc); res = calc->lcm (res, v); } return res; } // Function: lcm Value func_lcm (valVector args, ValueCalc *calc, FuncExtra *) { Value result = 0; for (unsigned int i = 0; i < args.count(); ++i) if (args[i].isArray()) result = calc->lcm (result, func_lcm_helper (args[i], calc)); else result = calc->lcm (result, args[i]); return result; } Value determinant (ValueCalc *calc, Value matrix) { // this is a --- SLOOOW --- recursive function // using this for something bigger than 10x10 or so = suicide :P // but I'm too lazy to adjust gnumeric's code - remains as a TODO then // as a note, gnumeric uses LUP decomposition to compute this // take first row, generate smaller matrices, recursion, multiply Value res = 0.0; int n = matrix.columns(); if (n == 1) return matrix.element (0, 0); if (n == 2) return calc->sub ( calc->mul (matrix.element (1,1), matrix.element (0,0)), calc->mul (matrix.element (1,0), matrix.element (0,1))); // n >= 3 for (int i = 0; i < n; ++i) { Value smaller (n-1, n-1); int col = 0; for (int c = 0; c < n; ++c) if (c != i) { // copy column c to column col in new matrix for (int r = 1; r < n; r++) smaller.setElement (col, r-1, matrix.element (c, r)); col++; } Value minor = determinant (calc, smaller); if (i % 2 == 1) minor = calc->mul (minor, -1); res = calc->add (res, calc->mul (minor, matrix.element (i, 0))); } return res; } // Function: mdeterm Value func_mdeterm (valVector args, ValueCalc *calc, FuncExtra *) { Value m = args[0]; unsigned r = m.rows (); unsigned c = m.columns (); if (r != c) // must be a square matrix return Value::errorVALUE(); return determinant (calc, args[0]); } // Function: mmult Value func_mmult (valVector args, ValueCalc *calc, FuncExtra *) { Value m1 = args[0]; Value m2 = args[1]; unsigned r1 = m1.rows (); unsigned c1 = m1.columns (); unsigned r2 = m2.rows (); unsigned c2 = m2.columns (); if (c1 != r2) // row/column counts must match return Value::errorVALUE(); // create the resulting matrix Value res (c2, r1); // perform the multiplication - O(n^3) algorithm for (uint row = 0; row < r1; ++row) for (uint col = 0; col < c2; ++col) { Value val = 0.0; for (uint pos = 0; pos < c1; ++pos) val = calc->add (val, calc->mul (m1.element (pos, row), m2.element (col, pos))); res.setElement (col, row, val); } return res; } // Function: SUBTOTAL // This function requires access to the Sheet and so on, because // it needs to check whether cells contain the SUBTOTAL formula or not ... // Cells containing a SUBTOTAL formula must be ignored. Value func_subtotal (valVector args, ValueCalc *calc, FuncExtra *e) { int function = calc->conv()->asInteger (args[0]).asInteger(); Value range = args[1]; int r1 = -1, c1 = -1, r2 = -1, c2 = -1; if (e) { r1 = e->ranges[1].row1; c1 = e->ranges[1].col1; r2 = e->ranges[1].row2; c2 = e->ranges[1].col2; } // if we have a range, run through it, and put an empty value to the place // of all occurences of the SUBTOTAL function Value empty; if ((r1 > 0) && (c1 > 0) && (r2 > 0) && (c2 > 0)) { for (int r = r1; r <= r2; ++r) for (int c = c1; c <= c2; ++c) { Cell *cell = e->sheet->cellAt (c, r); if (cell->isDefault()) continue; if (cell->isFormula() && cell->text().find ("SUBTOTAL", 0, false) != -1) // cell contains the word SUBTOTAL - replace value with empty range.setElement (c-c1, r-r1, empty); } } // Good. Now we can execute the necessary function on the range. Value res; Function *f; valVector a; switch (function) { case 1: // Average res = calc->avg (range, false); break; case 2: // Count res = calc->count (range, false); break; case 3: // CountA res = calc->count (range); break; case 4: // MAX res = calc->max (range, false); break; case 5: // Min res = calc->min (range, false); break; case 6: // Product res = calc->product (range, 0.0, false); break; case 7: // StDev res = calc->stddev (range, false); break; case 8: // StDevP res = calc->stddevP (range, false); break; case 9: // Sum res = calc->sum (range, false); break; case 10: // Var f = FunctionRepository::self()->function ("VAR"); if (!f) return Value::errorVALUE(); a.reserve (1); a[0] = range; res = f->exec (a, calc, 0); break; case 11: // VarP f = FunctionRepository::self()->function ("VARP"); if (!f) return Value::errorVALUE(); a.reserve (1); a[0] = range; res = f->exec (a, calc, 0); break; default: return Value::errorVALUE(); } return res; } /* Commented out. Absolutely no idea what this thing is supposed to do. To anyone who would enable this code: it still uses koscript calls - you need to convert it to the new style prior to uncommenting. // Function: MULTIPLEOPERATIONS Value func_multipleOP (valVector args, ValueCalc *calc, FuncExtra *) { if (gCell) { context.setValue( new KSValue( ((Interpreter *) context.interpreter() )->cell()->value().asFloat() ) ); return true; } gCell = ((Interpreter *) context.interpreter() )->cell(); TQValueList& args = context.value()->listValue(); TQValueList& extra = context.extraData()->listValue(); if ( !KSUtil::checkArgumentsCount( context, 5, "MULTIPLEOPERATIONS", true ) ) { gCell = 0; return false; } // 0: cell must contain formula with double/int result // 0, 1, 2, 3, 4: must contain integer/double for (int i = 0; i < 5; ++i) { if ( !KSUtil::checkType( context, args[i], KSValue::DoubleType, true ) ) { gCell = 0; return false; } } // ((Interpreter *) context.interpreter() )->document()->emitBeginOperation(); double oldCol = args[1]->doubleValue(); double oldRow = args[3]->doubleValue(); kdDebug() << "Old values: Col: " << oldCol << ", Row: " << oldRow << endl; Cell * cell; Sheet * sheet = ((Interpreter *) context.interpreter() )->sheet(); Point point( extra[1]->stringValue() ); Point point2( extra[3]->stringValue() ); Point point3( extra[0]->stringValue() ); if ( ( args[1]->doubleValue() != args[2]->doubleValue() ) || ( args[3]->doubleValue() != args[4]->doubleValue() ) ) { cell = sheet->cellAt( point.pos.x(), point.pos.y() ); cell->setValue( args[2]->doubleValue() ); kdDebug() << "Setting value " << args[2]->doubleValue() << " on cell " << point.pos.x() << ", " << point.pos.y() << endl; cell = sheet->cellAt( point2.pos.x(), point.pos.y() ); cell->setValue( args[4]->doubleValue() ); kdDebug() << "Setting value " << args[4]->doubleValue() << " on cell " << point2.pos.x() << ", " << point2.pos.y() << endl; } Cell * cell1 = sheet->cellAt( point3.pos.x(), point3.pos.y() ); cell1->calc( false ); double d = cell1->value().asFloat(); kdDebug() << "Cell: " << point3.pos.x() << "; " << point3.pos.y() << " with value " << d << endl; kdDebug() << "Resetting old values" << endl; cell = sheet->cellAt( point.pos.x(), point.pos.y() ); cell->setValue( oldCol ); cell = sheet->cellAt( point2.pos.x(), point2.pos.y() ); cell->setValue( oldRow ); cell1->calc( false ); // ((Interpreter *) context.interpreter() )->document()->emitEndOperation(); context.setValue( new KSValue( (double) d ) ); gCell = 0; return true; } */