/******************************************************************** This file is part of the abs 0.907 distribution. abs is a spreadsheet with graphical user interface. Copyright (C) 1998-2001 André Bertin (Andre.Bertin@ping.be) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version if in the same spirit as version 2. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Concact: abs@pi.be http://home.pi.be/bertin/abs.shtml *********************************************************************/ #include "mathfct.h" #include "y.tab.h" #include "string.h" #include "math.h" #include "cell_vb.h" #include "typedef.h" #include "application.h" #include "interpret.h" #include "gram_ext.h" #include "abv.h" #include "parser_ext.h" Fct matharrayfct[] = { {"ABS", &vb_ABS, 1, 1, "ABS(number)", "Returns the absolute value of a number"}, {"ACOS", &vb_ACOS, 1, 1, NULL, NULL}, {"ACOSH", &vb_ACOSH, 1, 1, NULL, NULL}, {"ASIN", &vb_ASIN, 1, 1, NULL, NULL}, {"ASINH", &vb_ASINH, 1, 1, NULL, NULL}, {"ATAN", &vb_ATAN, 1, 1, NULL, NULL}, {"ATAN2", &vb_ATAN2, 1, 1, NULL, NULL}, {"ATANH", &vb_ATANH, 1, 1, NULL, NULL}, {"CEILING", &vb_CEILING, 1, 1, NULL, NULL}, {"COMBIN", &vb_COMBIN, 1, 1, NULL, NULL}, {"COS", &vb_COS, 1, 1, NULL, NULL}, {"COSH", &vb_COSH, 1, 1, NULL, NULL}, {"COUNTIF", &vb_COUNTIF, 1, 1, NULL, NULL}, {"DEGREES", &vb_DEGREES, 1, 1, NULL, NULL}, {"EVEN", &vb_EVEN, 1, 1, NULL, NULL}, {"EXP", &vb_EXP, 1, 1, NULL, NULL}, {"FACT", &vb_FACT, 1, 1, NULL, NULL}, {"FACTDOUBLE", &vb_FACTDOUBLE, 1, 1, NULL, NULL}, {"FLOOR", &vb_FLOOR, 1, 1, NULL, NULL}, {"GCD", &vb_GCD, 1, 1, NULL, NULL}, {"INT", &vb_INT, 1, 1, NULL, NULL}, {"LCM", &vb_LCM, 1, 1, NULL, NULL}, {"LN", &vb_LN, 1, 1, NULL, NULL}, {"LOG10", &vb_LOG10, 1, 1, NULL, NULL}, {"LOG", &vb_LOG, 1, 1, NULL, NULL}, {"MDETERM", &vb_MDETERM, 1, 1, NULL, NULL}, {"MINVERSE", &vb_MINVERSE, 1, 1, NULL, NULL}, {"MMULT", &vb_MMULT, 1, 1, NULL, NULL}, {"MOD", &vb_MOD, 1, 1, NULL, NULL}, {"MROUND", &vb_MROUND, 1, 1, NULL, NULL}, {"MULTINOMIAL", &vb_MULTINOMIAL, 1, 1, NULL, NULL}, {"ODD", &vb_ODD, 1, 1, NULL, NULL}, {"PI", &vb_PI, 1, 1, NULL, NULL}, {"POWER", &vb_POWER, 1, 1, NULL, NULL}, {"PRODUCT", &vb_PRODUCT, 1, 1, NULL, NULL}, {"QUOTIENT", &vb_QUOTIENT, 1, 1, NULL, NULL}, {"RADIANS", &vb_RADIANS, 1, 1, NULL, NULL}, {"RAND", &vb_RAND, 1, 1, NULL, NULL}, {"RANDBETWEEN", &vb_RANDBETWEEN, 1, 1, NULL, NULL}, {"ROMAN", &vb_ROMAN, 1, 1, NULL, NULL}, {"ROUND", &vb_ROUND, 1, 1, NULL, NULL}, {"ROUNDDOWN", &vb_ROUNDDOWN, 1, 1, NULL, NULL}, {"ROUNDUP", &vb_ROUNDUP, 1, 1, NULL, NULL}, {"SERIESSUM", &vb_SERIESSUM, 1, 1, NULL, NULL}, {"SIGN", &vb_SIGN, 1, 1, NULL, NULL}, {"SIN", &vb_SIN, 1, 1, NULL, NULL}, {"SINH", &vb_SINH, 1, 1, NULL, NULL}, {"SQRT", &vb_SQRT, 1, 1, NULL, NULL}, {"SQRTPI", &vb_SQRTPI, 1, 1, NULL, NULL}, {"SUM", &vb_SUM, 1, 1, NULL, NULL}, {"SUMIF", &vb_SUMIF, 1, 1, NULL, NULL}, {"SUMPRODUCT", &vb_SUMPRODUCT, 1, 1, NULL, NULL}, {"SUMSQ", &vb_SUMSQ, 1, 1, NULL, NULL}, {"SUMX2MY2", &vb_SUMX2MY2, 1, 1, NULL, NULL}, {"SUMX2PY2", &vb_SUMX2PY2, 1, 1, NULL, NULL}, {"SUMXMY2", &vb_SUMXMY2, 1, 1, NULL, NULL}, {"TAN", &vb_TAN, 1, 1, NULL, NULL}, {"TANH", &vb_TANH, 1, 1, NULL, NULL}, {"TRUNC", &vb_TRUNC, 1, 1, NULL, NULL}, {NULL, NULL, 0, 0, NULL, NULL}, }; #ifndef PI #define PI 3.14159265359 #endif int makeif (obj value, char *criteria) { obj val; int doit = 0; char *formula = NULL; int len = 0; int ret = 0; if (criteria == NULL) return 0; len = strlen (criteria); switch (value.type) { case INTEGER: formula = (char *) absmalloc ((len + 20) * sizeof (char), "makeif:formula"); sprintf (formula, "%d%s", value.rec.i, criteria); doit = 1; break; case DOUBLE: formula = (char *) absmalloc ((len + 32) * sizeof (char), "makeif:formula"); sprintf (formula, "%f%s", value.rec.d, criteria); doit = 1; break; case STRING_CONSTANT: if (value.rec.s == NULL) break; formula = (char *) absmalloc ((len + strlen (value.rec.s) + 8) * sizeof (char), "makeif:formula"); sprintf (formula, "\"%s\"=\"%s\"", value.rec.s, criteria); doit = 1; break; } if (doit) { seteqboolean (); val = exint (parseexpression (formula)); unseteqboolean (); if (obj2int (val)) ret = 1; absfree (formula, "makeif:formula"); } return ret; } obj vb_ABS (int narg, obj * arg) { obj o; o.rec.d = abs (obj2double (arg[0])); o.type = DOUBLE; return o; } obj vb_ACOS (int narg, obj * arg) { obj o; o.rec.d = acos (obj2double (arg[0])); o.type = DOUBLE; return o; } obj vb_ACOSH (int narg, obj * arg) { obj o; o.rec.d = acosh (obj2double (arg[0])); o.type = DOUBLE; return o; } obj vb_ASIN (int narg, obj * arg) { obj o; o.rec.d = asin (obj2double (arg[0])); o.type = DOUBLE; return o; } obj vb_ASINH (int narg, obj * arg) { obj o; o.rec.d = asinh (obj2double (arg[0])); o.type = DOUBLE; return o; } obj vb_ATAN (int narg, obj * arg) { obj o; o.rec.d = atan (obj2double (arg[0])); o.type = DOUBLE; return o; } obj vb_ATAN2 (int narg, obj * arg) { obj o; o.rec.d = atan2 (obj2double (arg[0]), obj2double (arg[1])); o.type = DOUBLE; return o; } obj vb_ATANH (int narg, obj * arg) { obj o; o.rec.d = atanh (obj2double (arg[0])); o.type = DOUBLE; return o; } obj vb_CEILING (int narg, obj * arg) { obj o; double nombre = obj2double (arg[0]); double multiple = obj2double (arg[1]); double tmp = 0.0; int n = 0; if (nombre * multiple > 0) { tmp = multiple; while (fabs (tmp) < fabs (nombre) && n < 1000) { tmp *= fabs (multiple); n++; } tmp /= multiple; } o.rec.d = tmp; o.type = DOUBLE; return o; } int fact (int n) { int i; int val = 1.0; for (i = 2; i <= n && i < 200; i++) val *= i; return val; } obj vb_COMBIN (int narg, obj * arg) { obj o; int n; int k; double a, b; k = obj2int (arg[1]); n = obj2int (arg[0]); if (n > 0 && k > 0 && n > k) { a = fact (n); b = fact (k) * fact (n - k); o.rec.d = a / b; } else { o.rec.d = 0; } o.type = DOUBLE; return o; } obj vb_COS (int narg, obj * arg) { obj o; o.rec.d = cos (obj2double (arg[0])); o.type = DOUBLE; return o; } obj vb_COSH (int narg, obj * arg) { obj o; o.rec.d = cosh (obj2double (arg[0])); o.type = DOUBLE; return o; } obj vb_COUNTIF (int narg, obj * arg) { obj o; obj tmp; int i, r, c; int ret = 0; tmpRange *ran; o.type = INTEGER; o.rec.i = 0; if (narg < 2) return o; if (arg[0].type != STRING_CONSTANT && arg[0].type != STRING) return o; if (arg[0].rec.s == NULL) return o; for (i = 1; i < narg; i++) { if (arg[i].type == RANGE) { ran = (tmpRange *) arg[i].rec.s; if (ran->wks == NULL) { for (r = ran->r1; r <= ran->r2; r++) for (c = ran->c1; c <= ran->c2; c++) { tmp = get_ovalue (r, c); ret += makeif (tmp, arg[0].rec.s); } } else { for (r = ran->r1; r <= ran->r2; r++) for (c = ran->c1; c <= ran->c2; c++) { tmp = get_ovalue_wks (ran->wks, r, c); ret += makeif (tmp, arg[0].rec.s); } } } else { tmp = id2val (arg[i]); ret += makeif (tmp, arg[0].rec.s); } } o.rec.i = ret; return o; } obj vb_DEGREES (int narg, obj * arg) { obj o; o.rec.d = 180.0 / PI * (obj2double (arg[0])); o.type = DOUBLE; return o; } obj vb_EVEN (int narg, obj * arg) { obj o; ABVInform ("EVEN not yet implemented"); o.type = DOUBLE; return o; } obj vb_EXP (int narg, obj * arg) { obj o; double x, y; x = obj2double (arg[0]); y = obj2double (arg[1]); o.rec.d = pow (x, y); o.type = DOUBLE; return o; } obj vb_FACT (int narg, obj * arg) { obj o; o.rec.d = fact (obj2int (arg[0])); o.type = DOUBLE; return o; } obj vb_FACTDOUBLE (int narg, obj * arg) { obj o; o.rec.d = fact (obj2int (arg[0])); o.type = DOUBLE; return o; } obj vb_FLOOR (int narg, obj * arg) { obj o; o.rec.d = floor (obj2double (arg[0])); o.type = DOUBLE; return o; } obj vb_GCD (int narg, obj * arg) { obj o; int i; int f = 1; double div = 2; while (f) { for (i = 0; i < narg; i++) { if (fmod (obj2double (arg[0]), div) != 0) f = 0; } div++; } div--; o.rec.d = div; o.type = DOUBLE; return o; } obj vb_INT (int narg, obj * arg) { obj o; double val = obj2double (arg[0]); o.rec.d = rint (val); o.type = DOUBLE; return o; } obj vb_LCM (int narg, obj * arg) { obj o; ABVInform ("LCM not yet implemented"); o.type = DOUBLE; return o; } obj vb_LN (int narg, obj * arg) { obj o; o.rec.d = log (obj2double (arg[0])); o.type = DOUBLE; return o; } obj vb_LOG (int narg, obj * arg) { obj o; o.rec.d = log10 (obj2double (arg[0])); o.type = DOUBLE; return o; } obj vb_LOG10 (int narg, obj * arg) { obj o; o.rec.d = log10 (obj2double (arg[0])); o.type = DOUBLE; return o; } obj vb_MDETERM (int narg, obj * arg) { obj o; ABVInform ("MDETERM not yet implemented"); o.type = DOUBLE; return o; } obj vb_MINVERSE (int narg, obj * arg) { obj o; ABVInform ("MINVERSE not yet implemented"); o.type = DOUBLE; return o; } obj vb_MMULT (int narg, obj * arg) { obj o; ABVInform ("MMULT not yet implemented"); o.type = DOUBLE; return o; } obj vb_MOD (int narg, obj * arg) { obj o; o.rec.d = fmod (obj2double (arg[0]), obj2double (arg[1])); o.type = DOUBLE; return o; } obj vb_MROUND (int narg, obj * arg) { obj o; ABVInform (" MROUND not yet implemented"); o.type = DOUBLE; return o; } obj vb_MULTINOMIAL (int narg, obj * arg) { obj o; ABVInform ("MULTINOMIAL not yet implemented"); o.type = DOUBLE; return o; } obj vb_ODD (int narg, obj * arg) { obj o; ABVInform ("ODD not yet implemented"); o.type = DOUBLE; return o; } obj vb_PI (int narg, obj * arg) { obj o; o.rec.d = PI; o.type = DOUBLE; return o; } obj vb_POWER (int narg, obj * arg) { obj o; o.rec.d = pow (obj2double (arg[0]), obj2double (arg[1])); o.type = DOUBLE; return o; } obj vb_PRODUCT (int narg, obj * arg) { obj o; int r, c; tmpRange *ran; double val = 1; int i; for (i = 0; i < narg; i++) { if (arg[i].type == RANGE) { ran = (tmpRange *) arg[i].rec.s; if (ran->wks == NULL) { for (r = ran->r1; r <= ran->r2; r++) for (c = ran->c1; c <= ran->c2; c++) val *= get_value (r, c); } else { for (r = ran->r1; r <= ran->r2; r++) for (c = ran->c1; c <= ran->c2; c++) val *= get_value_wks (ran->wks, r, c); } } else val *= obj2double (arg[i]); } o.rec.d = val; o.type = DOUBLE; return o; } obj vb_QUOTIENT (int narg, obj * arg) { obj o; o.rec.d = 0.0; o.type = DOUBLE; return o; } obj vb_RADIANS (int narg, obj * arg) { obj o; o.rec.d = PI / 180.0 * (obj2double (arg[0])); o.type = DOUBLE; return o; } obj vb_RAND (int narg, obj * arg) { obj o; o.rec.d = 0.0 + (1.0 * rand () / (RAND_MAX + 1.0)); o.type = DOUBLE; return o; } obj vb_RANDBETWEEN (int narg, obj * arg) { obj o; double low = obj2double (arg[0]); double up = obj2double (arg[1]); o.rec.d = low + (up * rand () / (RAND_MAX + 1.0)); o.type = DOUBLE; return o; } obj vb_ROMAN (int narg, obj * arg) { obj o; ABVInform ("ROMAN not yet implemented"); o.type = DOUBLE; return o; } obj vb_ROUND (int narg, obj * arg) { obj o; double val = obj2double (arg[0]); double ndeci = 0; int valint; if (narg > 1) ndeci = obj2double (arg[1]); if (ndeci >= 0) { valint = rint (val * pow (10, ndeci)); val = valint * pow (10, -ndeci); } o.rec.d = val; o.type = DOUBLE; return o; } obj vb_ROUNDDOWN (int narg, obj * arg) { obj o; double val = obj2double (arg[0]); double ndeci = 0; if (narg > 1) ndeci = obj2double (arg[1]); if (ndeci >= 0) { val *= pow (10, ndeci); val = floor (val); val *= pow (10, -ndeci); } o.rec.d = val; o.type = DOUBLE; return o; } obj vb_ROUNDUP (int narg, obj * arg) { obj o; double val = obj2double (arg[0]); double ndeci = 0; if (narg > 1) ndeci = obj2double (arg[1]); if (ndeci >= 0) { val *= pow (10, ndeci); val = ceil (val); val *= pow (10, -ndeci); } o.rec.d = val; o.type = DOUBLE; return o; } obj vb_SERIESSUM (int narg, obj * arg) { obj o; ABVInform ("SERIESSUM not yet implemented"); o.type = DOUBLE; return o; } obj vb_SIGN (int narg, obj * arg) { obj o; double val = obj2double (arg[0]); if (val > 0) o.rec.d = 1; else if (val < 0) o.rec.d = -1; else o.rec.d = 0; o.type = DOUBLE; return o; } obj vb_SIN (int narg, obj * arg) { obj o; o.rec.d = sin (obj2double (arg[0])); o.type = DOUBLE; return o; } obj vb_SINH (int narg, obj * arg) { obj o; o.rec.d = sinh (obj2double (arg[0])); o.type = DOUBLE; return o; } obj vb_SQRT (int narg, obj * arg) { obj o; o.rec.d = sqrt (obj2double (arg[0])); o.type = DOUBLE; return o; } obj vb_SQRTPI (int narg, obj * arg) { obj o; o.rec.d = sqrt (PI * obj2double (arg[0])); o.type = DOUBLE; return o; } obj vb_SUM (int narg, obj * arg) { obj o; int r, c; tmpRange *ran; double val = 0; int i; for (i = 0; i < narg; i++) { if (arg[i].type == RANGE) { ran = (tmpRange *) arg[i].rec.s; if (ran->wks == NULL) { for (r = ran->r1; r <= ran->r2; r++) for (c = ran->c1; c <= ran->c2; c++) val += get_value (r, c); } else { for (r = ran->r1; r <= ran->r2; r++) for (c = ran->c1; c <= ran->c2; c++) val += get_value_wks (ran->wks, r, c); } } else val += obj2double (arg[i]); } o.rec.d = val; o.type = DOUBLE; return o; } obj vb_SUMIF (int narg, obj * arg) { obj o; obj tmp; int i, r, c; double ret = 0; tmpRange *ran; o.type = DOUBLE; o.rec.d = 0; if (narg < 2) return o; if (arg[0].type != STRING_CONSTANT && arg[0].type != STRING) return o; if (arg[0].rec.s == NULL) return o; for (i = 1; i < narg; i++) { if (arg[i].type == RANGE) { ran = (tmpRange *) arg[i].rec.s; if (ran->wks == NULL) { for (r = ran->r1; r <= ran->r2; r++) for (c = ran->c1; c <= ran->c2; c++) { tmp = get_ovalue (r, c); if (makeif (tmp, arg[0].rec.s)) ret += obj2double (tmp); } } else { for (r = ran->r1; r <= ran->r2; r++) for (c = ran->c1; c <= ran->c2; c++) { tmp = get_ovalue_wks (ran->wks, r, c); if (makeif (tmp, arg[0].rec.s)) ret += obj2double (tmp); } } } else { tmp = id2val (arg[i]); if (makeif (tmp, arg[0].rec.s)) ret += obj2double (tmp); } } o.rec.d = ret; return o; } obj vb_SUMPRODUCT (int narg, obj * arg) { obj o; ABVInform ("SUMPRODUCT not yet implemented"); o.type = DOUBLE; return o; } obj vb_SUMSQ (int narg, obj * arg) { obj o; int r, c; tmpRange *ran; double val = 0; int i; double tmp; for (i = 0; i < narg; i++) { if (arg[i].type == RANGE) { ran = (tmpRange *) arg[i].rec.s; if (ran->wks == NULL) { for (r = ran->r1; r <= ran->r2; r++) for (c = ran->c1; c <= ran->c2; c++) { tmp = get_value (r, c); val += tmp * tmp; } } else { for (r = ran->r1; r <= ran->r2; r++) for (c = ran->c1; c <= ran->c2; c++) { tmp = get_value_wks (ran->wks, r, c); val += tmp * tmp; } } } else { tmp = obj2double (arg[i]); val += tmp * tmp; } } o.rec.d = val; o.type = DOUBLE; return o; } obj vb_SUMX2MY2 (int narg, obj * arg) { obj o; ABVInform ("SUMX2MY2 not yet implemented"); o.type = DOUBLE; return o; } obj vb_SUMX2PY2 (int narg, obj * arg) { obj o; ABVInform ("SUMX2PY2 not yet implemented"); o.type = DOUBLE; return o; } obj vb_SUMXMY2 (int narg, obj * arg) { obj o; ABVInform ("SUMXMY2 not yet implemented"); o.type = DOUBLE; return o; } obj vb_TAN (int narg, obj * arg) { obj o; o.rec.d = tan (obj2double (arg[0])); o.type = DOUBLE; return o; } obj vb_TANH (int narg, obj * arg) { obj o; o.rec.d = tanh (obj2double (arg[0])); o.type = DOUBLE; return o; } obj vb_TRUNC (int narg, obj * arg) { obj o; double val = obj2double (arg[0]); double ndeci = 0; int valint; if (narg > 1) ndeci = obj2double (arg[1]); if (ndeci >= 0) { valint = val * pow (10, ndeci); val = valint * pow (10, -ndeci); } o.rec.d = val; o.type = DOUBLE; return o; }