Deriv: cleanups.
[gnumeric.git] / plugins / fn-math / functions.c
blob7a7c7e3119e7921d6ab18660c4a996c9bb4c7d39
1 /*
2 * fn-math.c: Built in mathematical functions and functions registration
4 * Authors:
5 * Miguel de Icaza (miguel@gnu.org)
6 * Jukka-Pekka Iivonen (iivonen@iki.fi)
7 * Morten Welinder (terra@gnome.org)
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, see <https://www.gnu.org/licenses/>.
22 #include <gnumeric-config.h>
23 #include <gnumeric.h>
24 #include <func.h>
25 #include <cell.h>
26 #include <sheet.h>
27 #include <workbook.h>
28 #include <mathfunc.h>
29 #include <sf-trig.h>
30 #include <sf-gamma.h>
31 #include <rangefunc.h>
32 #include <collect.h>
33 #include <value.h>
34 #include <criteria.h>
35 #include <expr.h>
36 #include <expr-deriv.h>
37 #include <position.h>
38 #include <regression.h>
39 #include <gnm-i18n.h>
41 #include <goffice/goffice.h>
42 #include <gnm-plugin.h>
44 #include <math.h>
45 #include <string.h>
47 #define UNICODE_PI "\360\235\234\213"
48 #define UNICODE_MINUS "\xe2\x88\x92"
50 GNM_PLUGIN_MODULE_HEADER;
52 #define FUNCTION_A_DESC GNM_FUNC_HELP_DESCRIPTION, F_("Numbers, text and logical values are " \
53 "included in the calculation too. If the cell contains text or " \
54 "the argument evaluates to FALSE, it is counted as value zero (0). " \
55 "If the argument evaluates to TRUE, it is counted as one (1).")
57 /***************************************************************************/
59 static GnmValue *
60 oldstyle_if_func (GnmFuncEvalInfo *ei, GnmValue const * const *argv,
61 float_range_function_t fun, GnmStdError err,
62 CollectFlags flags)
64 GPtrArray *crits = g_ptr_array_new_with_free_func ((GDestroyNotify)gnm_criteria_unref);
65 GPtrArray *data = g_ptr_array_new ();
66 GODateConventions const *date_conv =
67 sheet_date_conv (ei->pos->sheet);
68 GnmValue *res;
69 gboolean insanity;
70 GnmValue const *vals;
72 g_ptr_array_add (data, (gpointer)(argv[0]));
73 g_ptr_array_add (crits, parse_criteria (argv[1], date_conv, TRUE));
75 if (argv[2]) {
76 vals = argv[2];
77 insanity = (value_area_get_width (vals, ei->pos) != value_area_get_width (argv[0], ei->pos) ||
78 value_area_get_height (vals, ei->pos) != value_area_get_height (argv[0], ei->pos));
79 if (insanity) {
80 // The value area is the wrong size, but this function
81 // is *documented* to use an area of the right size
82 // with the same starting point. That's absolutely
83 // insane -- for starters, we are tracking the wrong
84 // dependents.
86 // For now, bail.
87 res = value_new_error_VALUE (ei->pos);
88 goto out;
90 } else {
91 vals = argv[0];
92 insanity = FALSE;
95 res = gnm_ifs_func (data, crits, vals,
96 fun, err, ei->pos,
97 flags);
99 out:
100 g_ptr_array_free (data, TRUE);
101 g_ptr_array_free (crits, TRUE);
103 return res;
106 static GnmValue *
107 newstyle_if_func (GnmFuncEvalInfo *ei, int argc, GnmExprConstPtr const *argv,
108 float_range_function_t fun, GnmStdError err,
109 gboolean no_data)
111 GPtrArray *crits = g_ptr_array_new_with_free_func ((GDestroyNotify)gnm_criteria_unref);
112 GPtrArray *data = g_ptr_array_new_with_free_func ((GDestroyNotify)value_release);
113 GODateConventions const *date_conv =
114 sheet_date_conv (ei->pos->sheet);
115 GnmValue *res;
116 GnmValue *vals = NULL;
117 int i;
118 int cstart = no_data ? 0 : 1;
120 if ((argc - cstart) & 1) {
121 res = value_new_error_VALUE (ei->pos);
122 goto out;
125 if (!no_data) {
126 vals = gnm_expr_eval (argv[0], ei->pos,
127 GNM_EXPR_EVAL_PERMIT_NON_SCALAR |
128 GNM_EXPR_EVAL_WANT_REF);
129 if (VALUE_IS_ERROR (vals)) {
130 res = value_dup (vals);
131 goto out;
133 if (!VALUE_IS_CELLRANGE (vals)) {
134 res = value_new_error_VALUE (ei->pos);
135 goto out;
139 for (i = cstart; i + 1 < argc; i += 2) {
140 GnmValue *area, *crit;
142 area = gnm_expr_eval (argv[i], ei->pos,
143 GNM_EXPR_EVAL_PERMIT_NON_SCALAR |
144 GNM_EXPR_EVAL_WANT_REF);
145 if (VALUE_IS_ERROR (area)) {
146 res = area;
147 goto out;
149 if (no_data && !vals)
150 vals = value_dup (area);
151 g_ptr_array_add (data, area);
153 crit = gnm_expr_eval (argv[i + 1], ei->pos,
154 GNM_EXPR_EVAL_SCALAR_NON_EMPTY);
155 if (VALUE_IS_ERROR (crit)) {
156 res = crit;
157 goto out;
160 g_ptr_array_add (crits, parse_criteria (crit, date_conv, TRUE));
161 value_release (crit);
164 if (!vals) {
165 // COUNTIFS with no arguments.
166 res = value_new_error_VALUE (ei->pos);
167 goto out;
170 res = gnm_ifs_func (data, crits, vals,
171 fun, err, ei->pos,
172 (no_data
174 : COLLECT_IGNORE_STRINGS |
175 COLLECT_IGNORE_BLANKS |
176 COLLECT_IGNORE_BOOLS));
178 out:
179 g_ptr_array_free (data, TRUE);
180 g_ptr_array_free (crits, TRUE);
181 value_release (vals);
183 return res;
186 /***************************************************************************/
188 static GnmFuncHelp const help_gcd[] = {
189 { GNM_FUNC_HELP_NAME, F_("GCD:the greatest common divisor")},
190 { GNM_FUNC_HELP_ARG, F_("n0:positive integer")},
191 { GNM_FUNC_HELP_ARG, F_("n1:positive integer")},
192 { GNM_FUNC_HELP_DESCRIPTION, F_("GCD calculates the greatest common divisor of the given numbers @{n0},@{n1},..., the greatest integer that is a divisor of each argument.")},
193 { GNM_FUNC_HELP_NOTE, F_("If any of the arguments is not an integer, it is truncated.")},
194 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
195 { GNM_FUNC_HELP_EXAMPLES, "=GCD(470,770)" },
196 { GNM_FUNC_HELP_EXAMPLES, "=GCD(470,770,1495)" },
197 { GNM_FUNC_HELP_SEEALSO, "LCM"},
198 { GNM_FUNC_HELP_END}
201 static const gnm_float gnm_gcd_max = 1 / GNM_EPSILON;
203 static gnm_float
204 gnm_gcd (gnm_float a, gnm_float b)
206 while (b > 0.5) {
207 gnm_float r = gnm_fmod (a, b);
208 a = b;
209 b = r;
211 return a;
214 static int
215 range_gcd (gnm_float const *xs, int n, gnm_float *res)
217 if (n > 0) {
218 int i;
219 gnm_float gcd_so_far = gnm_fake_floor (xs[0]);
221 for (i = 0; i < n; i++) {
222 gnm_float thisx = gnm_fake_floor (xs[i]);
223 if (thisx < 0 || thisx > gnm_gcd_max)
224 return 1;
225 else
226 gcd_so_far = gnm_gcd (thisx, gcd_so_far);
229 if (gcd_so_far == 0)
230 return 1;
232 *res = gcd_so_far;
233 return 0;
234 } else
235 return 1;
238 static GnmValue *
239 gnumeric_gcd (GnmFuncEvalInfo *ei, int argc, GnmExprConstPtr const *argv)
241 return float_range_function (argc, argv, ei,
242 range_gcd,
243 COLLECT_IGNORE_STRINGS |
244 COLLECT_IGNORE_BOOLS |
245 COLLECT_IGNORE_BLANKS,
246 GNM_ERROR_NUM);
249 /***************************************************************************/
251 static GnmFuncHelp const help_lcm[] = {
252 { GNM_FUNC_HELP_NAME, F_("LCM:the least common multiple")},
253 { GNM_FUNC_HELP_ARG, F_("n0:positive integer")},
254 { GNM_FUNC_HELP_ARG, F_("n1:positive integer")},
255 { GNM_FUNC_HELP_DESCRIPTION, F_("LCM calculates the least common multiple of the given numbers @{n0},@{n1},..., the smallest integer that is a multiple of each argument.")},
256 { GNM_FUNC_HELP_NOTE, F_("If any of the arguments is not an integer, it is truncated.")},
257 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
258 { GNM_FUNC_HELP_EXAMPLES, "=LCM(2,13)" },
259 { GNM_FUNC_HELP_EXAMPLES, "=LCM(4,7,5)" },
260 { GNM_FUNC_HELP_SEEALSO, "GCD"},
261 { GNM_FUNC_HELP_END}
264 static gnm_float
265 gnm_lcm (gnm_float a, gnm_float b)
267 return a * (b / gnm_gcd (a, b));
270 static int
271 range_lcm (gnm_float const *xs, int n, gnm_float *res)
273 int i;
274 gnm_float lcm;
276 if (n <= 0)
277 return 1;
279 lcm = 1;
280 for (i = 0; i < n; i++) {
281 gnm_float thisx = gnm_fake_floor (xs[i]);
282 if (thisx == 1)
283 continue;
284 if (thisx < 1 || thisx > gnm_gcd_max || lcm > gnm_gcd_max)
285 return 1;
286 lcm = gnm_lcm (lcm, thisx);
289 *res = lcm;
290 return 0;
293 static GnmValue *
294 gnumeric_lcm (GnmFuncEvalInfo *ei, int argc, GnmExprConstPtr const *argv)
296 return float_range_function (argc, argv, ei,
297 range_lcm,
298 COLLECT_IGNORE_STRINGS |
299 COLLECT_IGNORE_BOOLS |
300 COLLECT_IGNORE_BLANKS,
301 GNM_ERROR_NUM);
305 /***************************************************************************/
307 static GnmFuncHelp const help_gd[] = {
308 { GNM_FUNC_HELP_NAME, F_("GD:Gudermannian function")},
309 { GNM_FUNC_HELP_ARG, F_("x:value")},
310 { GNM_FUNC_HELP_EXAMPLES, "=GD(0.5)" },
311 { GNM_FUNC_HELP_SEEALSO, "TAN,TANH" },
312 { GNM_FUNC_HELP_EXTREF, F_("wolfram:Gudermannian.html") },
313 { GNM_FUNC_HELP_EXTREF, F_("wiki:en:Gudermannian_function") },
314 { GNM_FUNC_HELP_END }
317 static gnm_float
318 gnm_gd (gnm_float x)
320 return 2 * gnm_atan (gnm_tanh (x / 2));
323 static GnmValue *
324 gnumeric_gd (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
326 return value_new_float (gnm_gd (value_get_as_float (argv[0])));
329 /***************************************************************************/
331 static GnmFuncHelp const help_hypot[] = {
332 { GNM_FUNC_HELP_NAME, F_("HYPOT:the square root of the sum of the squares of the arguments")},
333 { GNM_FUNC_HELP_ARG, F_("n0:number")},
334 { GNM_FUNC_HELP_ARG, F_("n1:number")},
335 { GNM_FUNC_HELP_EXAMPLES, "=HYPOT(3,4)" },
336 { GNM_FUNC_HELP_SEEALSO, "MIN,MAX"},
337 { GNM_FUNC_HELP_END}
340 static GnmValue *
341 gnumeric_hypot (GnmFuncEvalInfo *ei, int argc, GnmExprConstPtr const *argv)
343 return float_range_function (argc, argv, ei,
344 gnm_range_hypot,
345 COLLECT_IGNORE_STRINGS |
346 COLLECT_IGNORE_BOOLS |
347 COLLECT_IGNORE_BLANKS,
348 GNM_ERROR_NUM);
352 /***************************************************************************/
354 static GnmFuncHelp const help_abs[] = {
355 { GNM_FUNC_HELP_NAME, F_("ABS:absolute value")},
356 { GNM_FUNC_HELP_ARG, F_("x:number")},
357 { GNM_FUNC_HELP_DESCRIPTION, F_("ABS gives the absolute value of @{x}, i.e. the non-negative number of the same magnitude as @{x}.")},
358 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
359 { GNM_FUNC_HELP_EXAMPLES, "=ABS(7)" },
360 { GNM_FUNC_HELP_EXAMPLES, "=ABS(-3.14)" },
361 { GNM_FUNC_HELP_SEEALSO, "CEIL,CEILING,FLOOR,INT,MOD"},
362 { GNM_FUNC_HELP_END}
365 static GnmValue *
366 gnumeric_abs (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
368 return value_new_float (gnm_abs (value_get_as_float (argv[0])));
371 /***************************************************************************/
373 static GnmFuncHelp const help_acos[] = {
374 { GNM_FUNC_HELP_NAME, F_("ACOS:the arc cosine of @{x}")},
375 { GNM_FUNC_HELP_ARG, F_("x:number")},
376 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
377 { GNM_FUNC_HELP_EXAMPLES, "=ACOS(0.1)" },
378 { GNM_FUNC_HELP_EXAMPLES, "=ACOS(-0.1)" },
379 { GNM_FUNC_HELP_SEEALSO, "COS,SIN,DEGREES,RADIANS"},
380 { GNM_FUNC_HELP_END}
383 static GnmValue *
384 gnumeric_acos (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
386 gnm_float t = value_get_as_float (argv[0]);
388 if (t < -1.0 || t > 1.0)
389 return value_new_error_NUM (ei->pos);
390 return value_new_float (gnm_acos (t));
393 /***************************************************************************/
395 static GnmFuncHelp const help_acosh[] = {
396 { GNM_FUNC_HELP_NAME, F_("ACOSH:the hyperbolic arc cosine of @{x}")},
397 { GNM_FUNC_HELP_ARG, F_("x:number")},
398 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
399 { GNM_FUNC_HELP_EXAMPLES, "=ACOSH(1.1)" },
400 { GNM_FUNC_HELP_EXAMPLES, "=ACOSH(6.1)" },
401 { GNM_FUNC_HELP_SEEALSO, "ACOS,ASINH"},
402 { GNM_FUNC_HELP_END}
405 static GnmValue *
406 gnumeric_acosh (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
408 gnm_float t = value_get_as_float (argv[0]);
410 if (t < 1.0)
411 return value_new_error_NUM (ei->pos);
413 return value_new_float (gnm_acosh (t));
416 /***************************************************************************/
418 static GnmFuncHelp const help_acot[] = {
419 { GNM_FUNC_HELP_NAME, F_("ACOT:inverse cotangent of @{x}")},
420 { GNM_FUNC_HELP_ARG, F_("x:value")},
421 { GNM_FUNC_HELP_EXAMPLES, "=ACOT(0.2)" },
422 { GNM_FUNC_HELP_SEEALSO, "COT,TAN" },
423 { GNM_FUNC_HELP_EXTREF, F_("wolfram:InverseCotangent.html") },
424 { GNM_FUNC_HELP_EXTREF, F_("wiki:en:Trigonometric_functions") },
425 { GNM_FUNC_HELP_END }
428 static GnmValue *
429 gnumeric_acot (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
431 return value_new_float (gnm_acot (value_get_as_float (argv[0])));
434 /***************************************************************************/
436 static GnmFuncHelp const help_acoth[] = {
437 { GNM_FUNC_HELP_NAME, F_("ACOTH:the inverse hyperbolic cotangent of @{x}")},
438 { GNM_FUNC_HELP_ARG, F_("x:number")},
439 { GNM_FUNC_HELP_EXAMPLES, "=ACOTH(2.2)" },
440 { GNM_FUNC_HELP_SEEALSO, "COTH,TANH" },
441 { GNM_FUNC_HELP_EXTREF, F_("wolfram:InverseHyperbolicCotangent.html") },
442 { GNM_FUNC_HELP_EXTREF, F_("wiki:en:Inverse_hyperbolic_function") },
443 { GNM_FUNC_HELP_END }
446 static GnmValue *
447 gnumeric_acoth (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
449 return value_new_float (gnm_acoth (value_get_as_float (argv[0])));
452 /***************************************************************************/
454 static GnmFuncHelp const help_asin[] = {
455 { GNM_FUNC_HELP_NAME, F_("ASIN:the arc sine of @{x}")},
456 { GNM_FUNC_HELP_ARG, F_("x:number")},
457 { GNM_FUNC_HELP_DESCRIPTION, F_("ASIN calculates the arc sine of @{x}; that is the value whose sine is @{x}.")},
458 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
459 { GNM_FUNC_HELP_NOTE, F_("If @{x} falls outside the range -1 to 1, "
460 "ASIN returns #NUM!") },
461 { GNM_FUNC_HELP_EXAMPLES, "=ASIN(0.5)" },
462 { GNM_FUNC_HELP_EXAMPLES, "=ASIN(1)" },
463 { GNM_FUNC_HELP_SEEALSO, "SIN,COS,ASINH,DEGREES,RADIANS"},
464 { GNM_FUNC_HELP_END}
467 static GnmValue *
468 gnumeric_asin (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
470 gnm_float t = value_get_as_float (argv[0]);
472 if (t < -1.0 || t > 1.0)
473 return value_new_error_NUM (ei->pos);
475 return value_new_float (gnm_asin (t));
478 /***************************************************************************/
480 static GnmFuncHelp const help_asinh[] = {
481 { GNM_FUNC_HELP_NAME, F_("ASINH:the inverse hyperbolic sine of @{x}")},
482 { GNM_FUNC_HELP_ARG, F_("x:number")},
483 { GNM_FUNC_HELP_DESCRIPTION, F_("ASINH calculates the inverse hyperbolic sine of @{x}; that is the value whose hyperbolic sine is @{x}.")},
484 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
485 { GNM_FUNC_HELP_EXAMPLES, "=ASINH(0.5)" },
486 { GNM_FUNC_HELP_EXAMPLES, "=ASINH(1)" },
487 { GNM_FUNC_HELP_SEEALSO, "ASIN,ACOSH,SIN,COS"},
488 { GNM_FUNC_HELP_END}
491 static GnmValue *
492 gnumeric_asinh (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
494 return value_new_float (gnm_asinh (value_get_as_float (argv[0])));
497 /***************************************************************************/
499 static GnmFuncHelp const help_atan[] = {
500 { GNM_FUNC_HELP_NAME, F_("ATAN:the arc tangent of @{x}")},
501 { GNM_FUNC_HELP_ARG, F_("x:number")},
502 { GNM_FUNC_HELP_DESCRIPTION, F_("ATAN calculates the arc tangent "
503 "of @{x}; that is the value whose "
504 "tangent is @{x}.")},
505 { GNM_FUNC_HELP_NOTE, F_("The result will be between "
506 "\xe2\x88\x92" "\xcf\x80" "/2 and "
507 "+" "\xcf\x80" "/2.")},
508 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
509 { GNM_FUNC_HELP_EXAMPLES, "=ATAN(0.5)" },
510 { GNM_FUNC_HELP_EXAMPLES, "=ATAN(1)" },
511 { GNM_FUNC_HELP_SEEALSO, "TAN,COS,SIN,DEGREES,RADIANS"},
512 { GNM_FUNC_HELP_END}
515 static GnmValue *
516 gnumeric_atan (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
518 return value_new_float (gnm_atan (value_get_as_float (argv[0])));
521 /***************************************************************************/
523 static GnmFuncHelp const help_atanh[] = {
524 { GNM_FUNC_HELP_NAME, F_("ATANH:the inverse hyperbolic tangent of @{x}")},
525 { GNM_FUNC_HELP_ARG, F_("x:number")},
526 { GNM_FUNC_HELP_DESCRIPTION, F_("ATANH calculates the inverse hyperbolic tangent of @{x}; that is the value whose hyperbolic tangent is @{x}.")},
527 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
528 { GNM_FUNC_HELP_NOTE, F_("If the absolute value of @{x} is greater than 1.0, ATANH returns #NUM!") },
529 { GNM_FUNC_HELP_EXAMPLES, "=ATANH(0.5)" },
530 { GNM_FUNC_HELP_EXAMPLES, "=ATANH(0.9)" },
531 { GNM_FUNC_HELP_SEEALSO, "ATAN,COS,SIN"},
532 { GNM_FUNC_HELP_END}
535 static GnmValue *
536 gnumeric_atanh (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
538 gnm_float t = value_get_as_float (argv[0]);
540 if (t <= -1.0 || t >= 1.0)
541 return value_new_error_NUM (ei->pos);
543 return value_new_float (gnm_atanh (value_get_as_float (argv[0])));
546 /***************************************************************************/
548 static GnmFuncHelp const help_atan2[] = {
549 { GNM_FUNC_HELP_NAME, F_("ATAN2:the arc tangent of the ratio "
550 "@{y}/@{x}")},
551 { GNM_FUNC_HELP_ARG, F_("x:x-coordinate")},
552 { GNM_FUNC_HELP_ARG, F_("y:y-coordinate")},
553 { GNM_FUNC_HELP_DESCRIPTION, F_("ATAN2 calculates the direction from "
554 "the origin to the point (@{x},@{y}) "
555 "as an angle from the x-axis in "
556 "radians.")},
557 { GNM_FUNC_HELP_NOTE, F_("The result will be between "
558 "\xe2\x88\x92" "\xcf\x80" " and "
559 "+" "\xcf\x80" ".")},
560 { GNM_FUNC_HELP_NOTE, F_("The order of the arguments may be "
561 "unexpected.")},
562 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
563 { GNM_FUNC_HELP_ODF, F_("This function is OpenFormula compatible.") },
564 { GNM_FUNC_HELP_EXAMPLES, "=ATAN2(0.5,1.0)" },
565 { GNM_FUNC_HELP_EXAMPLES, "=ATAN2(-0.5,2.0)" },
566 { GNM_FUNC_HELP_SEEALSO, "ATAN,ATANH,COS,SIN"},
567 { GNM_FUNC_HELP_END}
570 static GnmValue *
571 gnumeric_atan2 (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
573 gnm_float x = value_get_as_float (argv[0]);
574 gnm_float y = value_get_as_float (argv[1]);
576 if (x == 0 && y == 0)
577 return value_new_error_DIV0 (ei->pos);
579 return value_new_float (gnm_atan2 (y, x));
581 /***************************************************************************/
583 static GnmFuncHelp const help_agm[] = {
584 { GNM_FUNC_HELP_NAME, F_("AGM:the arithmetic-geometric mean") },
585 { GNM_FUNC_HELP_ARG, F_("a:value")},
586 { GNM_FUNC_HELP_ARG, F_("b:value")},
587 { GNM_FUNC_HELP_DESCRIPTION, F_("AGM computes the arithmetic-geometric mean of the two values.")},
588 { GNM_FUNC_HELP_EXAMPLES, "=AGM(1,4)" },
589 { GNM_FUNC_HELP_EXAMPLES, "=AGM(0.5,1)" },
590 { GNM_FUNC_HELP_SEEALSO, "AVERAGE,GEOMEAN"},
591 { GNM_FUNC_HELP_END}
594 static GnmValue *
595 gnumeric_agm (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
597 gnm_float a = value_get_as_float (argv[0]);
598 gnm_float b = value_get_as_float (argv[1]);
600 return value_new_float (agm (a, b));
603 /***************************************************************************/
605 static GnmFuncHelp const help_ceil[] = {
606 { GNM_FUNC_HELP_NAME, F_("CEIL:smallest integer larger than or equal to @{x}")},
607 { GNM_FUNC_HELP_ARG, F_("x:number")},
608 { GNM_FUNC_HELP_DESCRIPTION, F_("CEIL(@{x}) is the smallest integer that is at least as large as @{x}.")},
609 { GNM_FUNC_HELP_ODF, F_("This function is the OpenFormula function CEILING(@{x}).")},
610 { GNM_FUNC_HELP_EXAMPLES, "=CEIL(0.4)" },
611 { GNM_FUNC_HELP_EXAMPLES, "=CEIL(-1.1)" },
612 { GNM_FUNC_HELP_EXAMPLES, "=CEIL(-2.9)" },
613 { GNM_FUNC_HELP_SEEALSO, "CEILING,FLOOR,ABS,INT,MOD"},
614 { GNM_FUNC_HELP_END }
617 static GnmValue *
618 gnumeric_ceil (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
620 return value_new_float (gnm_fake_ceil (value_get_as_float (argv[0])));
623 /***************************************************************************/
625 static GnmFuncHelp const help_countif[] = {
626 { GNM_FUNC_HELP_NAME, F_("COUNTIF:count of the cells meeting the given @{criteria}")},
627 { GNM_FUNC_HELP_ARG, F_("range:cell area")},
628 { GNM_FUNC_HELP_ARG, F_("criteria:condition for a cell to be counted")},
629 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
630 { GNM_FUNC_HELP_SEEALSO, "COUNT,SUMIF"},
631 { GNM_FUNC_HELP_END}
634 static GnmValue *
635 gnumeric_countif (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
637 GnmValue const * argv3[3];
639 argv3[0] = argv[0];
640 argv3[1] = argv[1];
641 argv3[2] = NULL;
643 return oldstyle_if_func (ei, argv3, gnm_range_count, GNM_ERROR_DIV0,
647 /***************************************************************************/
649 static GnmFuncHelp const help_countifs[] = {
650 { GNM_FUNC_HELP_NAME, F_("COUNTIFS:count of the cells meeting the given @{criteria}")},
651 { GNM_FUNC_HELP_ARG, F_("range:cell area")},
652 { GNM_FUNC_HELP_ARG, F_("criteria:condition for a cell to be counted")},
653 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
654 { GNM_FUNC_HELP_SEEALSO, "COUNT,SUMIF"},
655 { GNM_FUNC_HELP_END}
658 static GnmValue *
659 gnumeric_countifs (GnmFuncEvalInfo *ei, int argc, GnmExprConstPtr const *argv)
661 return newstyle_if_func (ei, argc, argv,
662 gnm_range_count, GNM_ERROR_DIV0,
663 TRUE);
666 /***************************************************************************/
668 static GnmFuncHelp const help_sumif[] = {
669 { GNM_FUNC_HELP_NAME, F_("SUMIF:sum of the cells in @{actual_range} for which the corresponding cells in the range meet the given @{criteria}")},
670 { GNM_FUNC_HELP_ARG, F_("range:cell area")},
671 { GNM_FUNC_HELP_ARG, F_("criteria:condition for a cell to be summed")},
672 { GNM_FUNC_HELP_ARG, F_("actual_range:cell area, defaults to @{range}")},
673 { GNM_FUNC_HELP_NOTE, F_("If the @{actual_range} has a size that "
674 "differs"
675 " from the size of @{range}, @{actual_range} "
676 "is resized (retaining the top-left corner)"
677 " to match the size of @{range}.")},
678 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
679 { GNM_FUNC_HELP_SEEALSO, "SUM,SUMIFS,COUNTIF"},
680 { GNM_FUNC_HELP_END}
683 static GnmValue *
684 gnumeric_sumif (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
686 return oldstyle_if_func (ei, argv, gnm_range_sum, GNM_ERROR_DIV0,
687 COLLECT_IGNORE_STRINGS |
688 COLLECT_IGNORE_BLANKS |
689 COLLECT_IGNORE_BOOLS);
692 /***************************************************************************/
694 static GnmFuncHelp const help_sumifs[] = {
695 { GNM_FUNC_HELP_NAME, F_("SUMIFS:sum of the cells in @{actual_range} for which the corresponding cells in the range meet the given criteria")},
696 { GNM_FUNC_HELP_ARG, F_("actual_range:cell area")},
697 { GNM_FUNC_HELP_ARG, F_("range1:cell area")},
698 { GNM_FUNC_HELP_ARG, F_("criteria1:condition for a cell to be included")},
699 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
700 { GNM_FUNC_HELP_SEEALSO, "SUM,SUMIF"},
701 { GNM_FUNC_HELP_END}
704 static GnmValue *
705 gnumeric_sumifs (GnmFuncEvalInfo *ei, int argc, GnmExprConstPtr const *argv)
707 return newstyle_if_func (ei, argc, argv,
708 gnm_range_sum, GNM_ERROR_DIV0,
709 FALSE);
712 /***************************************************************************/
714 static GnmFuncHelp const help_averageif[] = {
715 { GNM_FUNC_HELP_NAME, F_("AVERAGEIF:average of the cells in @{actual range} for which the corresponding cells in the range meet the given @{criteria}")},
716 { GNM_FUNC_HELP_ARG, F_("range:cell area")},
717 { GNM_FUNC_HELP_ARG, F_("criteria:condition for a cell to be included")},
718 { GNM_FUNC_HELP_ARG, F_("actual_range:cell area, defaults to @{range}")},
719 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
720 { GNM_FUNC_HELP_SEEALSO, "SUMIF,COUNTIF"},
721 { GNM_FUNC_HELP_END}
724 static GnmValue *
725 gnumeric_averageif (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
727 return oldstyle_if_func (ei, argv, gnm_range_average, GNM_ERROR_DIV0,
728 COLLECT_IGNORE_STRINGS |
729 COLLECT_IGNORE_BLANKS |
730 COLLECT_IGNORE_BOOLS);
733 /***************************************************************************/
735 static GnmFuncHelp const help_averageifs[] = {
736 { GNM_FUNC_HELP_NAME, F_("AVERAGEIFS:average of the cells in @{actual_range} for which the corresponding cells in the range meet the given criteria")},
737 { GNM_FUNC_HELP_ARG, F_("actual_range:cell area")},
738 { GNM_FUNC_HELP_ARG, F_("range1:cell area")},
739 { GNM_FUNC_HELP_ARG, F_("criteria1:condition for a cell to be included")},
740 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
741 { GNM_FUNC_HELP_SEEALSO, "AVERAGE,AVERAGEIF"},
742 { GNM_FUNC_HELP_END}
745 static GnmValue *
746 gnumeric_averageifs (GnmFuncEvalInfo *ei, int argc, GnmExprConstPtr const *argv)
748 return newstyle_if_func (ei, argc, argv,
749 gnm_range_average, GNM_ERROR_DIV0,
750 FALSE);
753 /***************************************************************************/
755 static GnmFuncHelp const help_minifs[] = {
756 { GNM_FUNC_HELP_NAME, F_("MINIFS:minimum of the cells in @{actual_range} for which the corresponding cells in the range meet the given criteria")},
757 { GNM_FUNC_HELP_ARG, F_("actual_range:cell area")},
758 { GNM_FUNC_HELP_ARG, F_("range1:cell area")},
759 { GNM_FUNC_HELP_ARG, F_("criteria1:condition for a cell to be included")},
760 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
761 { GNM_FUNC_HELP_SEEALSO, "MIN,MAXIFS"},
762 { GNM_FUNC_HELP_END}
765 static GnmValue *
766 gnumeric_minifs (GnmFuncEvalInfo *ei, int argc, GnmExprConstPtr const *argv)
768 return newstyle_if_func (ei, argc, argv,
769 gnm_range_min, GNM_ERROR_DIV0,
770 FALSE);
773 /***************************************************************************/
775 static GnmFuncHelp const help_maxifs[] = {
776 { GNM_FUNC_HELP_NAME, F_("MAXIFS:maximum of the cells in @{actual_range} for which the corresponding cells in the range meet the given criteria")},
777 { GNM_FUNC_HELP_ARG, F_("actual_range:cell area")},
778 { GNM_FUNC_HELP_ARG, F_("range1:cell area")},
779 { GNM_FUNC_HELP_ARG, F_("criteria1:condition for a cell to be included")},
780 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
781 { GNM_FUNC_HELP_SEEALSO, "MIN,MINIFS"},
782 { GNM_FUNC_HELP_END}
785 static GnmValue *
786 gnumeric_maxifs (GnmFuncEvalInfo *ei, int argc, GnmExprConstPtr const *argv)
788 return newstyle_if_func (ei, argc, argv,
789 gnm_range_max, GNM_ERROR_DIV0,
790 FALSE);
793 /***************************************************************************/
795 static GnmFuncHelp const help_ceiling[] = {
796 { GNM_FUNC_HELP_NAME, F_("CEILING:nearest multiple of @{significance} whose absolute value is at least ABS(@{x})")},
797 { GNM_FUNC_HELP_ARG, F_("x:number")},
798 { GNM_FUNC_HELP_ARG, F_("significance:base multiple (defaults to 1 for @{x} > 0 and -1 for @{x} < 0)")},
799 { GNM_FUNC_HELP_DESCRIPTION, F_("CEILING(@{x},@{significance}) is the nearest multiple of @{significance} whose absolute value is at least ABS(@{x}).")},
800 { GNM_FUNC_HELP_NOTE, F_("If @{x} or @{significance} is non-numeric, CEILING returns a #VALUE! error.")},
801 { GNM_FUNC_HELP_NOTE, F_("If @{x} and @{significance} have different signs, CEILING returns a #NUM! error.")},
802 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.")},
803 { GNM_FUNC_HELP_ODF, F_("CEILING(@{x}) is exported to ODF as CEILING(@{x},SIGN(@{x}),1). CEILING(@{x},@{significance}) is the OpenFormula function CEILING(@{x},@{significance},1).")},
804 { GNM_FUNC_HELP_EXAMPLES, "=CEILING(2.43,1)" },
805 { GNM_FUNC_HELP_EXAMPLES, "=CEILING(123.123,3)" },
806 { GNM_FUNC_HELP_EXAMPLES, "=CEILING(-2.43,-1)" },
807 { GNM_FUNC_HELP_SEEALSO, "CEIL,FLOOR,ABS,INT,MOD"},
808 { GNM_FUNC_HELP_END }
811 static GnmValue *
812 gnumeric_ceiling (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
814 gnm_float x = value_get_as_float (argv[0]);
815 gnm_float s = argv[1] ? value_get_as_float (argv[1]) : (x > 0 ? 1 : -1);
817 if (x == 0 || s == 0)
818 return value_new_int (0);
820 if (x / s < 0)
821 return value_new_error_NUM (ei->pos);
823 return value_new_float (gnm_fake_ceil (x / s) * s);
826 /***************************************************************************/
828 static GnmFuncHelp const help_cos[] = {
829 { GNM_FUNC_HELP_NAME, F_("COS:the cosine of @{x}")},
830 { GNM_FUNC_HELP_ARG, F_("x:angle in radians")},
831 { GNM_FUNC_HELP_DESCRIPTION, F_("This function is Excel compatible.") },
832 { GNM_FUNC_HELP_EXTREF, F_("wolfram:Cosine.html") },
833 { GNM_FUNC_HELP_EXTREF, F_("wiki:en:Trigonometric_functions") },
834 { GNM_FUNC_HELP_EXAMPLES, "=COS(0.5)" },
835 { GNM_FUNC_HELP_EXAMPLES, "=COS(1)" },
836 { GNM_FUNC_HELP_SEEALSO, "SIN,TAN,SINH,COSH,TANH,RADIANS,DEGREES" },
837 { GNM_FUNC_HELP_END }
840 static GnmValue *
841 gnumeric_cos (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
843 return value_new_float (gnm_cos (value_get_as_float (argv[0])));
846 /***************************************************************************/
848 static GnmFuncHelp const help_cospi[] = {
849 { GNM_FUNC_HELP_NAME, F_("COSPI:the cosine of Pi*@{x}")},
850 { GNM_FUNC_HELP_ARG, F_("x:number of half turns")},
851 { GNM_FUNC_HELP_EXAMPLES, "=COSPI(0.5)" },
852 { GNM_FUNC_HELP_EXAMPLES, "=COSPI(1)" },
853 { GNM_FUNC_HELP_SEEALSO, "COS" },
854 { GNM_FUNC_HELP_END }
857 static GnmValue *
858 gnumeric_cospi (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
860 return value_new_float (gnm_cospi (value_get_as_float (argv[0])));
863 /***************************************************************************/
865 static GnmFuncHelp const help_cosh[] = {
866 { GNM_FUNC_HELP_NAME, F_("COSH:the hyperbolic cosine of @{x}")},
867 { GNM_FUNC_HELP_ARG, F_("x:number")},
868 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
869 { GNM_FUNC_HELP_EXAMPLES, "=COSH(0.5)" },
870 { GNM_FUNC_HELP_EXAMPLES, "=COSH(1)" },
871 { GNM_FUNC_HELP_SEEALSO, "SIN,TAN,SINH,COSH,TANH" },
872 { GNM_FUNC_HELP_END }
875 static GnmValue *
876 gnumeric_cosh (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
878 return value_new_float (gnm_cosh (value_get_as_float (argv[0])));
881 /***************************************************************************/
883 static GnmFuncHelp const help_cot[] = {
884 { GNM_FUNC_HELP_NAME, F_("COT:the cotangent of @{x}")},
885 { GNM_FUNC_HELP_ARG, F_("x:number")},
886 { GNM_FUNC_HELP_EXAMPLES, "=COT(0.12)" },
887 { GNM_FUNC_HELP_SEEALSO, "TAN,ACOT" },
888 { GNM_FUNC_HELP_EXTREF, F_("wolfram:Cotangent.html") },
889 { GNM_FUNC_HELP_EXTREF, F_("wiki:en:Trigonometric_functions") },
890 { GNM_FUNC_HELP_END }
893 static GnmValue *
894 gnumeric_cot (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
896 return value_new_float (gnm_cot (value_get_as_float (argv[0])));
899 /***************************************************************************/
901 static GnmFuncHelp const help_cotpi[] = {
902 { GNM_FUNC_HELP_NAME, F_("COTPI:the cotangent of Pi*@{x}")},
903 { GNM_FUNC_HELP_ARG, F_("x:number of half turns")},
904 { GNM_FUNC_HELP_EXAMPLES, "=COTPI(0.5)" },
905 { GNM_FUNC_HELP_EXAMPLES, "=COTPI(0.25)" },
906 { GNM_FUNC_HELP_SEEALSO, "COT" },
907 { GNM_FUNC_HELP_END }
910 static GnmValue *
911 gnumeric_cotpi (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
913 return value_new_float (gnm_cotpi (value_get_as_float (argv[0])));
916 /***************************************************************************/
918 static GnmFuncHelp const help_coth[] = {
919 { GNM_FUNC_HELP_NAME, F_("COTH:the hyperbolic cotangent of @{x}")},
920 { GNM_FUNC_HELP_ARG, F_("x:number")},
921 { GNM_FUNC_HELP_EXAMPLES, "=COTH(0.12)" },
922 { GNM_FUNC_HELP_SEEALSO, "TANH,ACOTH" },
923 { GNM_FUNC_HELP_EXTREF, F_("wolfram:HyperbolicCotangent.html") },
924 { GNM_FUNC_HELP_EXTREF, F_("wiki:en:Hyperbolic_function") },
925 { GNM_FUNC_HELP_END }
928 static GnmValue *
929 gnumeric_coth (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
931 return value_new_float (gnm_coth (value_get_as_float (argv[0])));
934 /***************************************************************************/
936 static GnmFuncHelp const help_degrees[] = {
937 { GNM_FUNC_HELP_NAME, F_("DEGREES:equivalent degrees to @{x} radians")},
938 { GNM_FUNC_HELP_ARG, F_("x:angle in radians")},
939 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
940 { GNM_FUNC_HELP_EXAMPLES, "=DEGREES(2.5)" },
941 { GNM_FUNC_HELP_SEEALSO, "RADIANS,PI"},
942 { GNM_FUNC_HELP_END}
945 static GnmValue *
946 gnumeric_degrees (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
948 return value_new_float ((value_get_as_float (argv[0]) * 180.0) /
949 M_PIgnum);
952 /***************************************************************************/
954 static GnmFuncHelp const help_exp[] = {
955 { GNM_FUNC_HELP_NAME, F_("EXP:e raised to the power of @{x}")},
956 { GNM_FUNC_HELP_ARG, F_("x:number")},
957 { GNM_FUNC_HELP_NOTE, F_("e is the base of the natural logarithm.") },
958 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
959 { GNM_FUNC_HELP_EXAMPLES, "=EXP(2)" },
960 { GNM_FUNC_HELP_SEEALSO, "LOG,LOG2,LOG10"},
961 { GNM_FUNC_HELP_END}
964 static GnmValue *
965 gnumeric_exp (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
967 return value_new_float (gnm_exp (value_get_as_float (argv[0])));
970 static GnmExpr const *
971 gnumeric_exp_deriv (GnmFunc *func, GnmExpr const *expr, GnmEvalPos const *ep,
972 GnmExprDeriv *info)
974 return gnm_expr_deriv_chain (expr, gnm_expr_copy (expr), ep, info);
977 /***************************************************************************/
979 static GnmFuncHelp const help_expm1[] = {
980 { GNM_FUNC_HELP_NAME, F_("EXPM1:EXP(@{x})-1")},
981 { GNM_FUNC_HELP_ARG, F_("x:number")},
982 { GNM_FUNC_HELP_NOTE, F_("This function has a higher resulting precision than evaluating EXP(@{x})-1.") },
983 { GNM_FUNC_HELP_EXAMPLES, "=EXPM1(0.01)" },
984 { GNM_FUNC_HELP_SEEALSO, "EXP,LN1P"},
985 { GNM_FUNC_HELP_END}
988 static GnmValue *
989 gnumeric_expm1 (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
991 return value_new_float (gnm_expm1 (value_get_as_float (argv[0])));
994 /***************************************************************************/
996 static GnmFuncHelp const help_fact[] = {
997 { GNM_FUNC_HELP_NAME, F_("FACT:the factorial of @{x}, i.e. @{x}!")},
998 { GNM_FUNC_HELP_ARG, F_("x:number")},
999 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
1000 { GNM_FUNC_HELP_NOTE, F_("The domain of this function has been extended using the GAMMA function.") },
1001 { GNM_FUNC_HELP_EXAMPLES, "=FACT(3)" },
1002 { GNM_FUNC_HELP_EXAMPLES, "=FACT(9)" },
1003 { GNM_FUNC_HELP_END}
1006 static GnmValue *
1007 gnumeric_fact (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1009 gnm_float x = value_get_as_float (argv[0]);
1010 gboolean x_is_integer = (x == gnm_floor (x));
1012 if (x < 0 && x_is_integer)
1013 return value_new_error_NUM (ei->pos);
1015 return value_new_float (gnm_fact (x));
1018 /***************************************************************************/
1020 static GnmFuncHelp const help_gamma[] = {
1021 { GNM_FUNC_HELP_NAME, F_("GAMMA:the Gamma function")},
1022 { GNM_FUNC_HELP_ARG, F_("x:number")},
1023 { GNM_FUNC_HELP_EXAMPLES, "=GAMMA(-1.8)" },
1024 { GNM_FUNC_HELP_EXAMPLES, "=GAMMA(2.4)" },
1025 { GNM_FUNC_HELP_SEEALSO, "GAMMALN"},
1026 { GNM_FUNC_HELP_END}
1029 static GnmValue *
1030 gnumeric_gamma (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1032 return value_new_float (gnm_gamma (value_get_as_float (argv[0])));
1035 /***************************************************************************/
1037 static GnmFuncHelp const help_gammaln[] = {
1038 { GNM_FUNC_HELP_NAME, F_("GAMMALN:natural logarithm of the Gamma function")},
1039 { GNM_FUNC_HELP_ARG, F_("x:number")},
1040 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
1041 { GNM_FUNC_HELP_EXAMPLES, "=GAMMALN(23)" },
1042 { GNM_FUNC_HELP_SEEALSO, "GAMMA"},
1043 { GNM_FUNC_HELP_END }
1046 static GnmValue *
1047 gnumeric_gammaln (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1049 gnm_float x = value_get_as_float (argv[0]);
1050 gboolean x_is_integer = (x == gnm_floor (x));
1052 if (x < 0 && (x_is_integer ||
1053 gnm_fmod (gnm_floor (-x), 2.0) == 0.0))
1054 return value_new_error_NUM (ei->pos);
1055 else
1056 return value_new_float (gnm_lgamma (x));
1059 /***************************************************************************/
1061 static GnmFuncHelp const help_igamma[] = {
1062 { GNM_FUNC_HELP_NAME, F_("IGAMMA:the incomplete Gamma function")},
1063 { GNM_FUNC_HELP_ARG, F_("a:number")},
1064 { GNM_FUNC_HELP_ARG, F_("x:number")},
1065 { GNM_FUNC_HELP_ARG, F_("lower:if true (the default), the lower incomplete gamma function, otherwise the upper incomplete gamma function")},
1066 { GNM_FUNC_HELP_ARG, F_("regularize:if true (the default), the regularized version of the incomplete gamma function")},
1067 { GNM_FUNC_HELP_ARG, F_("real:if true (the default), the real part of the result, otherwise the imaginary part")},
1068 { GNM_FUNC_HELP_NOTE, F_("The regularized incomplete gamma function is the unregularized incomplete gamma function divided by GAMMA(@{a})") },
1069 { GNM_FUNC_HELP_NOTE, F_("This is a real valued function as long as neither @{a} nor @{z} are negative.") },
1070 { GNM_FUNC_HELP_EXAMPLES, "=IGAMMA(2.5,-1.8,TRUE,TRUE,TRUE)" },
1071 { GNM_FUNC_HELP_EXAMPLES, "=IGAMMA(2.5,-1.8,TRUE,TRUE,FALSE)" },
1072 { GNM_FUNC_HELP_SEEALSO, "GAMMA,IMIGAMMA"},
1073 { GNM_FUNC_HELP_END}
1076 static GnmValue *
1077 gnumeric_igamma (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1079 gnm_float a = value_get_as_float (argv[0]);
1080 gnm_float z = value_get_as_float (argv[1]);
1081 gboolean lower = argv[2] ? value_get_as_checked_bool (argv[2]) : TRUE;
1082 gboolean reg = argv[3] ? value_get_as_checked_bool (argv[3]) : TRUE;
1083 gboolean re = argv[4] ? value_get_as_checked_bool (argv[4]) : TRUE;
1084 gnm_complex ig;
1086 ig = gnm_complex_igamma (GNM_CREAL (a), GNM_CREAL (z), lower, reg);
1088 return value_new_float (re ? ig.re : ig.im);
1091 /***************************************************************************/
1093 static GnmFuncHelp const help_beta[] = {
1094 { GNM_FUNC_HELP_NAME, F_("BETA:Euler beta function")},
1095 { GNM_FUNC_HELP_ARG, F_("x:number")},
1096 { GNM_FUNC_HELP_ARG, F_("y:number")},
1097 { GNM_FUNC_HELP_DESCRIPTION, F_("BETA function returns the value of the Euler beta function extended to all real numbers except 0 and negative integers.")},
1098 { GNM_FUNC_HELP_NOTE, F_("If @{x}, @{y}, or (@{x} + @{y}) are non-positive integers, BETA returns #NUM!") },
1099 { GNM_FUNC_HELP_EXAMPLES, "=BETA(2,3)" },
1100 { GNM_FUNC_HELP_EXAMPLES, "=BETA(-0.5,0.5)" },
1101 { GNM_FUNC_HELP_SEEALSO, "BETALN,GAMMALN"},
1102 { GNM_FUNC_HELP_EXTREF, F_("wiki:en:Beta_function") },
1103 { GNM_FUNC_HELP_END}
1106 static GnmValue *
1107 gnumeric_beta (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1109 gnm_float a = value_get_as_float (argv[0]);
1110 gnm_float b = value_get_as_float (argv[1]);
1112 return value_new_float (gnm_beta (a, b));
1115 /***************************************************************************/
1117 static GnmFuncHelp const help_betaln[] = {
1118 { GNM_FUNC_HELP_NAME, F_("BETALN:natural logarithm of the absolute value of the Euler beta function")},
1119 { GNM_FUNC_HELP_ARG, F_("x:number")},
1120 { GNM_FUNC_HELP_ARG, F_("y:number")},
1121 { GNM_FUNC_HELP_DESCRIPTION, F_("BETALN function returns the natural logarithm of the absolute value of the Euler beta function extended to all real numbers except 0 and negative integers.")},
1122 { GNM_FUNC_HELP_NOTE, F_("If @{x}, @{y}, or (@{x} + @{y}) are non-positive integers, BETALN returns #NUM!") },
1123 { GNM_FUNC_HELP_EXAMPLES, "=BETALN(2,3)" },
1124 { GNM_FUNC_HELP_EXAMPLES, "=BETALN(-0.5,0.5)" },
1125 { GNM_FUNC_HELP_SEEALSO, "BETA,GAMMALN"},
1126 { GNM_FUNC_HELP_EXTREF, F_("wiki:en:Beta_function") },
1127 { GNM_FUNC_HELP_END}
1130 static GnmValue *
1131 gnumeric_betaln (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1133 gnm_float a = value_get_as_float (argv[0]);
1134 gnm_float b = value_get_as_float (argv[1]);
1135 int sign;
1137 return value_new_float (gnm_lbeta3 (a, b, &sign));
1140 /***************************************************************************/
1142 static GnmFuncHelp const help_combin[] = {
1143 { GNM_FUNC_HELP_NAME, F_("COMBIN:binomial coefficient")},
1144 { GNM_FUNC_HELP_ARG, F_("n:non-negative integer")},
1145 { GNM_FUNC_HELP_ARG, F_("k:non-negative integer")},
1146 { GNM_FUNC_HELP_DESCRIPTION, F_("COMBIN returns the binomial coefficient \"@{n} choose @{k}\","
1147 " the number of @{k}-combinations of an @{n}-element set "
1148 "without repetition.")},
1149 { GNM_FUNC_HELP_NOTE, F_("If @{n} is less than @{k} COMBIN returns #NUM!") },
1150 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
1151 { GNM_FUNC_HELP_ODF, F_("This function is OpenFormula compatible.") },
1152 { GNM_FUNC_HELP_EXAMPLES, "=COMBIN(8,6)" },
1153 { GNM_FUNC_HELP_EXAMPLES, "=COMBIN(6,2)" },
1154 { GNM_FUNC_HELP_EXTREF, F_("wiki:en:Binomial_coefficient") },
1155 { GNM_FUNC_HELP_END}
1159 static GnmValue *
1160 gnumeric_combin (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1162 gnm_float n = gnm_floor (value_get_as_float (argv[0]));
1163 gnm_float k = gnm_floor (value_get_as_float (argv[1]));
1165 if (k >= 0 && n >= k)
1166 return value_new_float (combin (n ,k));
1168 return value_new_error_NUM (ei->pos);
1171 /***************************************************************************/
1173 static GnmFuncHelp const help_combina[] = {
1174 { GNM_FUNC_HELP_NAME, F_("COMBINA:the number of @{k}-combinations of an @{n}-element set "
1175 "with repetition")},
1176 { GNM_FUNC_HELP_ARG, F_("n:non-negative integer")},
1177 { GNM_FUNC_HELP_ARG, F_("k:non-negative integer")},
1178 { GNM_FUNC_HELP_ODF, F_("This function is OpenFormula compatible.") },
1179 { GNM_FUNC_HELP_EXAMPLES, "=COMBINA(5,3)" },
1180 { GNM_FUNC_HELP_EXAMPLES, "=COMBINA(6,3)" },
1181 { GNM_FUNC_HELP_EXAMPLES, "=COMBINA(42,3)" },
1182 { GNM_FUNC_HELP_EXTREF, F_("wiki:en:Multiset") },
1183 { GNM_FUNC_HELP_SEEALSO, "COMBIN" },
1184 { GNM_FUNC_HELP_END}
1188 static GnmValue *
1189 gnumeric_combina (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1191 gnm_float n = gnm_floor (value_get_as_float (argv[0]));
1192 gnm_float k = gnm_floor (value_get_as_float (argv[1]));
1194 if (k >= 0 && n >= 0)
1195 return value_new_float (combin (n + k - 1, k));
1197 return value_new_error_NUM (ei->pos);
1199 /***************************************************************************/
1201 static GnmFuncHelp const help_floor[] = {
1202 { GNM_FUNC_HELP_NAME, F_("FLOOR:nearest multiple of @{significance} whose absolute value is at most ABS(@{x})") },
1203 { GNM_FUNC_HELP_ARG, F_("x:number") },
1204 { GNM_FUNC_HELP_ARG, F_("significance:base multiple (defaults to 1 for @{x} > 0 and -1 for @{x} < 0)") },
1205 { GNM_FUNC_HELP_DESCRIPTION, F_(
1206 "FLOOR(@{x},@{significance}) is the nearest multiple of @{significance} whose absolute value is at most ABS(@{x})") },
1207 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.")},
1208 { GNM_FUNC_HELP_ODF, F_("FLOOR(@{x}) is exported to ODF as FLOOR(@{x},SIGN(@{x}),1). FLOOR(@{x},@{significance}) is the OpenFormula function FLOOR(@{x},@{significance},1).")},
1209 { GNM_FUNC_HELP_EXAMPLES, "=FLOOR(0.5)" },
1210 { GNM_FUNC_HELP_EXAMPLES, "=FLOOR(5,2)" },
1211 { GNM_FUNC_HELP_EXAMPLES, "=FLOOR(-5,-2)" },
1212 { GNM_FUNC_HELP_EXAMPLES, "=FLOOR(-5,2)" },
1213 { GNM_FUNC_HELP_SEEALSO, "CEIL,CEILING,ABS,INT,MOD" },
1214 { GNM_FUNC_HELP_END }
1217 static GnmValue *
1218 gnumeric_floor (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1220 gnm_float x = value_get_as_float (argv[0]);
1221 gnm_float s = argv[1] ? value_get_as_float (argv[1]) : (x > 0 ? 1 : -1);
1223 if (x == 0)
1224 return value_new_int (0);
1226 if (s == 0)
1227 return value_new_error_DIV0 (ei->pos);
1229 if (x / s < 0)
1230 return value_new_error_NUM (ei->pos);
1232 return value_new_float (gnm_fake_floor (x / s) * s);
1235 /***************************************************************************/
1237 static GnmFuncHelp const help_int[] = {
1238 { GNM_FUNC_HELP_NAME, F_("INT:largest integer not larger than @{x}")},
1239 { GNM_FUNC_HELP_ARG, F_("x:number")},
1240 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
1241 { GNM_FUNC_HELP_EXAMPLES, "=INT(7.2)" },
1242 { GNM_FUNC_HELP_EXAMPLES, "=INT(-5.5)" },
1243 { GNM_FUNC_HELP_SEEALSO, "CEIL,CEILING,FLOOR,ABS,MOD"},
1244 { GNM_FUNC_HELP_END}
1247 static GnmValue *
1248 gnumeric_int (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1250 return value_new_float (gnm_fake_floor
1251 (value_get_as_float (argv[0])));
1254 /***************************************************************************/
1256 static GnmFuncHelp const help_log[] = {
1257 { GNM_FUNC_HELP_NAME, F_("LOG:logarithm of @{x} with base @{base}")},
1258 { GNM_FUNC_HELP_ARG, F_("x:positive number")},
1259 { GNM_FUNC_HELP_ARG, F_("base:base of the logarithm, defaults to 10")},
1260 { GNM_FUNC_HELP_NOTE, F_("@{base} must be positive and not equal to 1.") },
1261 { GNM_FUNC_HELP_NOTE, F_("If @{x} \xe2\x89\xa4 0, LOG returns #NUM! error.") },
1262 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
1263 { GNM_FUNC_HELP_EXAMPLES, "=LOG(2)" },
1264 { GNM_FUNC_HELP_EXAMPLES, "=LOG(8192,2)" },
1265 { GNM_FUNC_HELP_SEEALSO, "LN,LOG2,LOG10"},
1266 { GNM_FUNC_HELP_END}
1269 static GnmValue *
1270 gnumeric_log (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1272 gnm_float t = value_get_as_float (argv[0]);
1273 gnm_float base = argv[1] ? value_get_as_float (argv[1]) : 10;
1274 gnm_float res;
1276 if (base == 1. || base <= 0.)
1277 return value_new_error_NUM (ei->pos);
1279 if (t <= 0.0)
1280 return value_new_error_NUM (ei->pos);
1282 if (base == 2)
1283 res = gnm_log2 (t);
1284 else if (base == 0.5)
1285 res = -gnm_log2 (t);
1286 else if (base == 10)
1287 res = gnm_log10 (t);
1288 else
1289 res = gnm_log (t) / gnm_log (base);
1291 return value_new_float (res);
1294 /***************************************************************************/
1296 static GnmFuncHelp const help_ln[] = {
1297 { GNM_FUNC_HELP_NAME, F_("LN:the natural logarithm of @{x}")},
1298 { GNM_FUNC_HELP_ARG, F_("x:positive number")},
1299 { GNM_FUNC_HELP_NOTE, F_("If @{x} \xe2\x89\xa4 0, LN returns #NUM! error.") },
1300 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
1301 { GNM_FUNC_HELP_EXAMPLES, "=LN(7)" },
1302 { GNM_FUNC_HELP_SEEALSO, "EXP,LOG2,LOG10"},
1303 { GNM_FUNC_HELP_END}
1306 static GnmValue *
1307 gnumeric_ln (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1309 gnm_float t = value_get_as_float (argv[0]);
1311 if (t <= 0.0)
1312 return value_new_error_NUM (ei->pos);
1314 return value_new_float (gnm_log (t));
1317 static GnmExpr const *
1318 gnumeric_ln_deriv (GnmExpr const *expr, GnmEvalPos const *ep,
1319 GnmExprDeriv *info, gpointer data)
1321 GnmExpr const *deriv =
1322 gnm_expr_new_binary (gnm_expr_new_constant (value_new_int (1)),
1323 GNM_EXPR_OP_DIV,
1324 gnm_expr_copy (gnm_expr_get_func_arg (expr, 0)));
1325 return gnm_expr_deriv_chain (expr, deriv, ep, info);
1328 /***************************************************************************/
1330 static GnmFuncHelp const help_ln1p[] = {
1331 { GNM_FUNC_HELP_NAME, F_("LN1P:LN(1+@{x})")},
1332 { GNM_FUNC_HELP_ARG, F_("x:positive number")},
1333 { GNM_FUNC_HELP_DESCRIPTION, F_("LN1P calculates LN(1+@{x}) but yielding a higher precision than evaluating LN(1+@{x}).")},
1334 { GNM_FUNC_HELP_NOTE, F_("If @{x} \xe2\x89\xa4 -1, LN returns #NUM! error.") },
1335 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
1336 { GNM_FUNC_HELP_EXAMPLES, "=LN1P(0.01)" },
1337 { GNM_FUNC_HELP_SEEALSO, "EXP,LN,EXPM1"},
1338 { GNM_FUNC_HELP_END}
1341 static GnmValue *
1342 gnumeric_ln1p (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1344 gnm_float t = value_get_as_float (argv[0]);
1346 if (t <= -1)
1347 return value_new_error_NUM (ei->pos);
1349 return value_new_float (gnm_log1p (t));
1352 /***************************************************************************/
1354 static GnmFuncHelp const help_power[] = {
1355 { GNM_FUNC_HELP_NAME, F_("POWER:the value of @{x} raised to the power @{y} raised to the power of 1/@{z}")},
1356 { GNM_FUNC_HELP_ARG, F_("x:number")},
1357 { GNM_FUNC_HELP_ARG, F_("y:number")},
1358 { GNM_FUNC_HELP_ARG, F_("z:number")},
1359 { GNM_FUNC_HELP_NOTE, F_("If both @{x} and @{y} equal 0, POWER returns #NUM!") },
1360 { GNM_FUNC_HELP_NOTE, F_("If @{x} = 0 and @{y} < 0, POWER returns #DIV/0!") },
1361 { GNM_FUNC_HELP_NOTE, F_("If @{x} < 0 and @{y} is not an integer, POWER returns #NUM!") },
1362 { GNM_FUNC_HELP_NOTE, F_("@{z} defaults to 1") },
1363 { GNM_FUNC_HELP_NOTE, F_("If @{z} is not a positive integer, POWER returns #NUM!") },
1364 { GNM_FUNC_HELP_NOTE, F_("If @{x} < 0, @{y} is odd, and @{z} is even, POWER returns #NUM!") },
1365 { GNM_FUNC_HELP_EXAMPLES, "=POWER(2,7)" },
1366 { GNM_FUNC_HELP_EXAMPLES, "=POWER(3,3.141)" },
1367 { GNM_FUNC_HELP_SEEALSO, "EXP"},
1368 { GNM_FUNC_HELP_END}
1371 static GnmValue *
1372 gnumeric_power (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1374 gnm_float x = value_get_as_float (argv[0]);
1375 gnm_float y = value_get_as_float (argv[1]);
1376 gnm_float z = argv[2] ? value_get_as_float (argv[2]) : 1;
1378 if ((x > 0) || (x == 0 && y > 0) || (x < 0 && y == gnm_floor (y))) {
1379 gnm_float r = gnm_pow (x, y);
1380 gboolean z_even = gnm_fmod (z, 2.0) == 0;
1381 if (z <= 0 || z != gnm_floor (z) || (r < 0 && z_even))
1382 return value_new_error_NUM (ei->pos);
1383 if (z != 1)
1384 r = (r < 0 ? -1 : +1) * gnm_pow (gnm_abs (r), 1 / z);
1385 return value_new_float (r);
1388 if (x == 0 && y != 0)
1389 return value_new_error_DIV0 (ei->pos);
1390 else
1391 return value_new_error_NUM (ei->pos);
1394 /***************************************************************************/
1396 static GnmFuncHelp const help_pochhammer[] = {
1397 { GNM_FUNC_HELP_NAME, F_("POCHHAMMER:the value of GAMMA(@{x}+@{n})/GAMMA(@{x})")},
1398 { GNM_FUNC_HELP_ARG, F_("x:number")},
1399 { GNM_FUNC_HELP_ARG, F_("n:number")},
1400 { GNM_FUNC_HELP_EXAMPLES, "=POCHHAMMER(1,5)" },
1401 { GNM_FUNC_HELP_EXAMPLES, "=POCHHAMMER(6,0.5)" },
1402 { GNM_FUNC_HELP_SEEALSO, "GAMMA"},
1403 { GNM_FUNC_HELP_END}
1406 static GnmValue *
1407 gnumeric_pochhammer (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1409 gnm_float x = value_get_as_float (argv[0]);
1410 gnm_float n = value_get_as_float (argv[1]);
1412 return value_new_float (pochhammer (x, n));
1415 /***************************************************************************/
1417 static GnmFuncHelp const help_log2[] = {
1418 { GNM_FUNC_HELP_NAME, F_("LOG2:the base-2 logarithm of @{x}")},
1419 { GNM_FUNC_HELP_ARG, F_("x:positive number")},
1420 { GNM_FUNC_HELP_NOTE, F_("If @{x} \xe2\x89\xa4 0, LOG2 returns #NUM!") },
1421 { GNM_FUNC_HELP_EXAMPLES, "=LOG2(1024)" },
1422 { GNM_FUNC_HELP_SEEALSO, "EXP,LOG10,LOG"},
1423 { GNM_FUNC_HELP_END}
1426 static GnmValue *
1427 gnumeric_log2 (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1429 gnm_float t = value_get_as_float (argv[0]);
1431 if (t <= 0.0)
1432 return value_new_error_NUM (ei->pos);
1434 return value_new_float (gnm_log2 (t));
1437 /***************************************************************************/
1439 static GnmFuncHelp const help_log10[] = {
1440 { GNM_FUNC_HELP_NAME, F_("LOG10:the base-10 logarithm of @{x}")},
1441 { GNM_FUNC_HELP_ARG, F_("x:positive number")},
1442 { GNM_FUNC_HELP_NOTE, F_("If @{x} \xe2\x89\xa4 0, LOG10 returns #NUM!") },
1443 { GNM_FUNC_HELP_EXAMPLES, "=LOG10(1024)" },
1444 { GNM_FUNC_HELP_SEEALSO, "EXP,LOG2,LOG"},
1445 { GNM_FUNC_HELP_END}
1448 static GnmValue *
1449 gnumeric_log10 (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1451 gnm_float t = value_get_as_float (argv[0]);
1453 if (t <= 0.0)
1454 return value_new_error_NUM (ei->pos);
1456 return value_new_float (gnm_log10 (t));
1459 /***************************************************************************/
1461 static GnmFuncHelp const help_mod[] = {
1462 { GNM_FUNC_HELP_NAME, F_("MOD:the remainder of @{x} under division by @{n}")},
1463 { GNM_FUNC_HELP_ARG, F_("x:integer")},
1464 { GNM_FUNC_HELP_ARG, F_("n:integer")},
1465 { GNM_FUNC_HELP_DESCRIPTION, F_("MOD function returns the remainder when @{x} is divided by @{n}.")},
1466 { GNM_FUNC_HELP_NOTE, F_("If @{n} is 0, MOD returns #DIV/0!")},
1467 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
1468 { GNM_FUNC_HELP_EXAMPLES, "=MOD(23,7)" },
1469 { GNM_FUNC_HELP_EXAMPLES, "=MOD(23,-7)" },
1470 { GNM_FUNC_HELP_SEEALSO, "CEIL,CEILING,FLOOR,ABS,INT,ABS"},
1471 { GNM_FUNC_HELP_END}
1475 * MOD(-1,-3) = -1
1476 * MOD(2,-3) = -2
1477 * MOD(10.6,2) = 0.6
1478 * MOD(-10.6,2) = 1.4
1479 * MOD(10.6,-2) = -0.6
1480 * MOD(-10.6,-2) = -1.4
1483 static GnmValue *
1484 gnumeric_mod (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1486 gnm_float a = value_get_as_float (argv[0]);
1487 gnm_float b = value_get_as_float (argv[1]);
1488 gnm_float babs, r;
1490 if (b == 0)
1491 return value_new_error_DIV0 (ei->pos);
1493 babs = gnm_abs (b);
1494 r = gnm_fmod (gnm_abs (a), babs);
1495 if (r > 0) {
1496 if ((a < 0) != (b < 0))
1497 r = babs - r;
1498 if (b < 0)
1499 r = -r;
1502 return value_new_float (r);
1505 /***************************************************************************/
1507 static GnmFuncHelp const help_radians[] = {
1508 { GNM_FUNC_HELP_NAME, F_("RADIANS:the number of radians equivalent to @{x} degrees")},
1509 { GNM_FUNC_HELP_ARG, F_("x:angle in degrees")},
1510 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
1511 { GNM_FUNC_HELP_EXAMPLES, "=RADIANS(180)" },
1512 { GNM_FUNC_HELP_SEEALSO, "PI,DEGREES"},
1513 { GNM_FUNC_HELP_END}
1516 static GnmValue *
1517 gnumeric_radians (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1519 return value_new_float ((value_get_as_float (argv[0]) * M_PIgnum) /
1520 180);
1523 /***************************************************************************/
1525 static GnmFuncHelp const help_reducepi[] = {
1526 { GNM_FUNC_HELP_NAME, F_("REDUCEPI:reduce modulo Pi divided by a power of 2")},
1527 { GNM_FUNC_HELP_ARG, F_("x:number")},
1528 { GNM_FUNC_HELP_ARG, F_("e:scale")},
1529 { GNM_FUNC_HELP_ARG, F_("q:get lower bits of quotient, defaults to FALSE")},
1530 { GNM_FUNC_HELP_EXAMPLES, "=REDUCEPI(10,1)" },
1531 { GNM_FUNC_HELP_NOTE, F_("This function returns a value, xr, such that @{x}=xr+j*Pi/2^@{e} where j is an integer and the absolute value of xr does not exceed Pi/2^(@{e}+1). If optional argument @{q} is TRUE, returns instead the @e+1 lower bits of j. The reduction is performed as-if using an exact value of Pi.")},
1532 { GNM_FUNC_HELP_NOTE, F_("The lowest valid @{e} is -1 representing reduction modulo 2*Pi; the highest is 7 representing reduction modulo Pi/256.")},
1533 { GNM_FUNC_HELP_SEEALSO, "PI"},
1534 { GNM_FUNC_HELP_END}
1537 static GnmValue *
1538 gnumeric_reducepi (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1540 gnm_float x = value_get_as_float (argv[0]);
1541 int e = value_get_as_int (argv[1]);
1542 gboolean q = argv[2] ? value_get_as_checked_bool (argv[2]) : FALSE;
1543 int j;
1544 gnm_float xr;
1546 if (e < -1 || e > 7)
1547 return value_new_error_VALUE (ei->pos);
1549 xr = gnm_reduce_pi (x, (int)e, &j);
1550 return q ? value_new_int (j) : value_new_float (xr);
1553 /***************************************************************************/
1555 static GnmFuncHelp const help_sin[] = {
1556 { GNM_FUNC_HELP_NAME, F_("SIN:the sine of @{x}")},
1557 { GNM_FUNC_HELP_ARG, F_("x:angle in radians")},
1558 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
1559 { GNM_FUNC_HELP_EXAMPLES, "=SIN(0.5)" },
1560 { GNM_FUNC_HELP_SEEALSO, "COS,TAN,CSC,SEC,SINH,COSH,TANH,RADIANS,DEGREES" },
1561 { GNM_FUNC_HELP_EXTREF, F_("wolfram:Sine.html") },
1562 { GNM_FUNC_HELP_EXTREF, F_("wiki:en:Trigonometric_functions") },
1563 { GNM_FUNC_HELP_END }
1566 static GnmValue *
1567 gnumeric_sin (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1569 return value_new_float (gnm_sin (value_get_as_float (argv[0])));
1572 /***************************************************************************/
1574 static GnmFuncHelp const help_sinpi[] = {
1575 { GNM_FUNC_HELP_NAME, F_("SINPI:the sine of Pi*@{x}")},
1576 { GNM_FUNC_HELP_ARG, F_("x:number of half turns")},
1577 { GNM_FUNC_HELP_EXAMPLES, "=SINPI(0.5)" },
1578 { GNM_FUNC_HELP_EXAMPLES, "=SINPI(1)" },
1579 { GNM_FUNC_HELP_SEEALSO, "SIN" },
1580 { GNM_FUNC_HELP_END }
1583 static GnmValue *
1584 gnumeric_sinpi (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1586 return value_new_float (gnm_sinpi (value_get_as_float (argv[0])));
1589 /***************************************************************************/
1591 static GnmFuncHelp const help_csc[] = {
1592 { GNM_FUNC_HELP_NAME, F_("CSC:the cosecant of @{x}")},
1593 { GNM_FUNC_HELP_ARG, F_("x:angle in radians")},
1594 { GNM_FUNC_HELP_EXCEL, F_("This function is not Excel compatible.") },
1595 { GNM_FUNC_HELP_ODF, F_("This function is OpenFormula compatible.") },
1596 { GNM_FUNC_HELP_EXAMPLES, "=CSC(0.5)" },
1597 { GNM_FUNC_HELP_SEEALSO, "SIN,COS,TAN,SEC,SINH,COSH,TANH,RADIANS,DEGREES" },
1598 { GNM_FUNC_HELP_EXTREF, F_("wolfram:Cosecant.html") },
1599 { GNM_FUNC_HELP_EXTREF, F_("wiki:en:Trigonometric_functions") },
1600 { GNM_FUNC_HELP_END }
1603 static GnmValue *
1604 gnumeric_csc (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1606 return value_new_float (1./gnm_sin (value_get_as_float (argv[0])));
1609 /***************************************************************************/
1611 static GnmFuncHelp const help_csch[] = {
1612 { GNM_FUNC_HELP_NAME, F_("CSCH:the hyperbolic cosecant of @{x}")},
1613 { GNM_FUNC_HELP_ARG, F_("x:number")},
1614 { GNM_FUNC_HELP_EXCEL, F_("This function is not Excel compatible.") },
1615 { GNM_FUNC_HELP_ODF, F_("This function is OpenFormula compatible.") },
1616 { GNM_FUNC_HELP_EXAMPLES, "=CSCH(0.5)" },
1617 { GNM_FUNC_HELP_SEEALSO, "SIN,COS,TAN,CSC,SEC,SINH,COSH,TANH" },
1618 { GNM_FUNC_HELP_EXTREF, F_("wolfram:HyperbolicCosecant.html") },
1619 { GNM_FUNC_HELP_EXTREF, F_("wiki:en:Hyperbolic_function") },
1620 { GNM_FUNC_HELP_END }
1623 static GnmValue *
1624 gnumeric_csch (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1626 return value_new_float (1./gnm_sinh (value_get_as_float (argv[0])));
1629 /***************************************************************************/
1631 static GnmFuncHelp const help_sec[] = {
1632 { GNM_FUNC_HELP_NAME, F_("SEC:Secant")},
1633 { GNM_FUNC_HELP_ARG, F_("x:angle in radians")},
1634 { GNM_FUNC_HELP_EXCEL, F_("This function is not Excel compatible.") },
1635 { GNM_FUNC_HELP_ODF, F_("SEC(@{x}) is exported to OpenFormula as 1/COS(@{x}).") },
1636 { GNM_FUNC_HELP_EXAMPLES, "=SEC(0.5)" },
1637 { GNM_FUNC_HELP_SEEALSO, "SIN,COS,TAN,CSC,SINH,COSH,TANH,RADIANS,DEGREES" },
1638 { GNM_FUNC_HELP_EXTREF, F_("wolfram:Secant.html") },
1639 { GNM_FUNC_HELP_EXTREF, F_("wiki:en:Trigonometric_functions") },
1640 { GNM_FUNC_HELP_END }
1643 static GnmValue *
1644 gnumeric_sec (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1646 return value_new_float (1./gnm_cos (value_get_as_float (argv[0])));
1649 /***************************************************************************/
1651 static GnmFuncHelp const help_sech[] = {
1652 { GNM_FUNC_HELP_NAME, F_("SECH:the hyperbolic secant of @{x}")},
1653 { GNM_FUNC_HELP_ARG, F_("x:number")},
1654 { GNM_FUNC_HELP_EXCEL, F_("This function is not Excel compatible.") },
1655 { GNM_FUNC_HELP_ODF, F_("SECH(@{x}) is exported to OpenFormula as 1/COSH(@{x}).") },
1656 { GNM_FUNC_HELP_EXAMPLES, "=SECH(0.5)" },
1657 { GNM_FUNC_HELP_SEEALSO, "SIN,COS,TAN,CSC,SEC,SINH,COSH,TANH" },
1658 { GNM_FUNC_HELP_EXTREF, F_("wolfram:HyperbolicSecant.html") },
1659 { GNM_FUNC_HELP_EXTREF, F_("wiki:en:Hyperbolic_function") },
1660 { GNM_FUNC_HELP_END }
1663 static GnmValue *
1664 gnumeric_sech (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1666 return value_new_float (1./gnm_cosh (value_get_as_float (argv[0])));
1668 /***************************************************************************/
1669 static GnmFuncHelp const help_sinh[] = {
1670 { GNM_FUNC_HELP_NAME, F_("SINH:the hyperbolic sine of @{x}")},
1671 { GNM_FUNC_HELP_ARG, F_("x:number")},
1672 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
1673 { GNM_FUNC_HELP_EXAMPLES, "=SINH(0.1)" },
1674 { GNM_FUNC_HELP_EXAMPLES, "=SINH(-0.1)" },
1675 { GNM_FUNC_HELP_SEEALSO, "SIN,COSH,ASINH"},
1676 { GNM_FUNC_HELP_END}
1679 static GnmValue *
1680 gnumeric_sinh (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1682 return value_new_float (gnm_sinh (value_get_as_float (argv[0])));
1685 /***************************************************************************/
1687 static GnmFuncHelp const help_sqrt[] = {
1688 { GNM_FUNC_HELP_NAME, F_("SQRT:square root of @{x}")},
1689 { GNM_FUNC_HELP_ARG, F_("x:non-negative number")},
1690 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
1691 { GNM_FUNC_HELP_NOTE, F_("If @{x} is negative, SQRT returns #NUM!")},
1692 { GNM_FUNC_HELP_EXAMPLES, "=SQRT(2)"},
1693 { GNM_FUNC_HELP_SEEALSO, "POWER"},
1694 { GNM_FUNC_HELP_END}
1697 static GnmValue *
1698 gnumeric_sqrt (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1700 gnm_float x = value_get_as_float (argv[0]);
1701 if (x < 0)
1702 return value_new_error_NUM (ei->pos);
1704 return value_new_float (gnm_sqrt (x));
1707 /***************************************************************************/
1709 static GnmFuncHelp const help_suma[] = {
1710 { GNM_FUNC_HELP_NAME, F_("SUMA:sum of all values and cells referenced")},
1711 { GNM_FUNC_HELP_ARG, F_("area0:first cell area")},
1712 { GNM_FUNC_HELP_ARG, F_("area1:second cell area")},
1713 { FUNCTION_A_DESC },
1714 { GNM_FUNC_HELP_EXAMPLES, "=SUMA(11,TRUE,FALSE,12)"},
1715 { GNM_FUNC_HELP_SEEALSO, "AVERAGE,SUM,COUNT"},
1716 { GNM_FUNC_HELP_END}
1720 static GnmValue *
1721 gnumeric_suma (GnmFuncEvalInfo *ei, int argc, GnmExprConstPtr const *argv)
1723 return float_range_function (argc, argv, ei,
1724 gnm_range_sum,
1725 COLLECT_ZERO_STRINGS |
1726 COLLECT_ZEROONE_BOOLS |
1727 COLLECT_IGNORE_BLANKS,
1728 GNM_ERROR_VALUE);
1731 /***************************************************************************/
1733 static GnmFuncHelp const help_sumsq[] = {
1734 { GNM_FUNC_HELP_NAME, F_("SUMSQ:sum of the squares of all values and cells referenced")},
1735 { GNM_FUNC_HELP_ARG, F_("area0:first cell area")},
1736 { GNM_FUNC_HELP_ARG, F_("area1:second cell area")},
1737 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
1738 { GNM_FUNC_HELP_EXAMPLES, "=SUMSQ(11,TRUE,FALSE,12)"},
1739 { GNM_FUNC_HELP_SEEALSO, "SUM,COUNT"},
1740 { GNM_FUNC_HELP_END}
1743 static GnmValue *
1744 gnumeric_sumsq (GnmFuncEvalInfo *ei, int argc, GnmExprConstPtr const *argv)
1746 return float_range_function (argc, argv, ei,
1747 gnm_range_sumsq,
1748 COLLECT_IGNORE_STRINGS |
1749 COLLECT_IGNORE_BOOLS |
1750 COLLECT_IGNORE_BLANKS,
1751 GNM_ERROR_VALUE);
1754 // Construct an equivalend expression
1755 static GnmExpr const *
1756 gnumeric_sumsq_equiv (GnmExpr const *expr, GnmEvalPos const *ep,
1757 GnmExprDeriv *info)
1759 GnmExprList *l, *args;
1760 GnmFunc *fsum = gnm_func_lookup ("SUM", NULL);
1762 if (!fsum) return NULL;
1764 args = gnm_expr_deriv_collect (expr, ep, info);
1765 for (l = args; l; l = l->next) {
1766 GnmExpr const *e = l->data;
1767 GnmExpr const *ee = gnm_expr_new_binary
1769 GNM_EXPR_OP_EXP,
1770 gnm_expr_new_constant (value_new_int (2)));
1771 l->data = (gpointer)ee;
1774 return gnm_expr_new_funcall (fsum, args);
1777 static GnmExpr const *
1778 gnumeric_sumsq_deriv (GnmFunc *func,
1779 GnmExpr const *expr, GnmEvalPos const *ep,
1780 GnmExprDeriv *info)
1782 GnmExpr const *sqsum = gnumeric_sumsq_equiv (expr, ep, info);
1783 if (sqsum) {
1784 GnmExpr const *res = gnm_expr_deriv (sqsum, ep, info);
1785 gnm_expr_free (sqsum);
1786 return res;
1787 } else
1788 return NULL;
1791 /***************************************************************************/
1793 static GnmFuncHelp const help_multinomial[] = {
1794 { GNM_FUNC_HELP_NAME, F_("MULTINOMIAL:multinomial coefficient (@{x1}+\xe2\x8b\xaf+@{xn}) choose (@{x1},\xe2\x80\xa6,@{xn})")},
1795 { GNM_FUNC_HELP_ARG, F_("x1:first number")},
1796 { GNM_FUNC_HELP_ARG, F_("x2:second number")},
1797 { GNM_FUNC_HELP_ARG, F_("xn:nth number")},
1798 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
1799 { GNM_FUNC_HELP_EXAMPLES, "=MULTINOMIAL(2,3,4)"},
1800 { GNM_FUNC_HELP_SEEALSO, "COMBIN,SUM"},
1801 { GNM_FUNC_HELP_EXTREF, F_("wiki:en:Multinomial_theorem") },
1802 { GNM_FUNC_HELP_END}
1805 static GnmValue *
1806 gnumeric_multinomial (GnmFuncEvalInfo *ei, int argc, GnmExprConstPtr const *argv)
1808 return float_range_function (argc, argv, ei,
1809 gnm_range_multinomial,
1810 COLLECT_IGNORE_STRINGS |
1811 COLLECT_IGNORE_BOOLS |
1812 COLLECT_IGNORE_BLANKS,
1813 GNM_ERROR_NUM);
1816 /***************************************************************************/
1818 static GnmFuncHelp const help_g_product[] = {
1819 { GNM_FUNC_HELP_NAME, F_("G_PRODUCT:product of all the values and cells referenced")},
1820 { GNM_FUNC_HELP_ARG, F_("x1:number")},
1821 { GNM_FUNC_HELP_ARG, F_("x2:number")},
1822 { GNM_FUNC_HELP_NOTE, F_("Empty cells are ignored and the empty product is 1.")},
1823 { GNM_FUNC_HELP_EXAMPLES, "=G_PRODUCT(2,5,9)"},
1824 { GNM_FUNC_HELP_SEEALSO, "SUM,COUNT"},
1825 { GNM_FUNC_HELP_END}
1828 static GnmValue *
1829 gnumeric_g_product (GnmFuncEvalInfo *ei, int argc, GnmExprConstPtr const *argv)
1831 return float_range_function (argc, argv, ei,
1832 gnm_range_product,
1833 COLLECT_IGNORE_STRINGS |
1834 COLLECT_IGNORE_BOOLS |
1835 COLLECT_IGNORE_BLANKS,
1836 GNM_ERROR_VALUE);
1839 /***************************************************************************/
1841 static GnmFuncHelp const help_tan[] = {
1842 { GNM_FUNC_HELP_NAME, F_("TAN:the tangent of @{x}")},
1843 { GNM_FUNC_HELP_ARG, F_("x:angle in radians")},
1844 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
1845 { GNM_FUNC_HELP_EXAMPLES, "=TAN(3)"},
1846 { GNM_FUNC_HELP_SEEALSO, "TANH,COS,COSH,SIN,SINH,DEGREES,RADIANS"},
1847 { GNM_FUNC_HELP_END}
1850 static GnmValue *
1851 gnumeric_tan (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1853 return value_new_float (gnm_tan (value_get_as_float (argv[0])));
1856 /***************************************************************************/
1858 static GnmFuncHelp const help_tanpi[] = {
1859 { GNM_FUNC_HELP_NAME, F_("TANPI:the tangent of Pi*@{x}")},
1860 { GNM_FUNC_HELP_ARG, F_("x:number of half turns")},
1861 { GNM_FUNC_HELP_EXAMPLES, "=TANPI(1)" },
1862 { GNM_FUNC_HELP_EXAMPLES, "=TANPI(0.25)" },
1863 { GNM_FUNC_HELP_SEEALSO, "TAN" },
1864 { GNM_FUNC_HELP_END }
1867 static GnmValue *
1868 gnumeric_tanpi (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1870 return value_new_float (gnm_tanpi (value_get_as_float (argv[0])));
1873 /***************************************************************************/
1874 static GnmFuncHelp const help_tanh[] = {
1875 { GNM_FUNC_HELP_NAME, F_("TANH:the hyperbolic tangent of @{x}")},
1876 { GNM_FUNC_HELP_ARG, F_("x:number")},
1877 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
1878 { GNM_FUNC_HELP_EXAMPLES, "=TANH(2)"},
1879 { GNM_FUNC_HELP_SEEALSO, "TAN,SIN,SINH,COS,COSH"},
1880 { GNM_FUNC_HELP_END}
1883 static GnmValue *
1884 gnumeric_tanh (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1886 return value_new_float (gnm_tanh (value_get_as_float (argv[0])));
1889 /***************************************************************************/
1891 static GnmFuncHelp const help_pi[] = {
1892 { GNM_FUNC_HELP_NAME, F_("PI:the constant " "\360\235\234\213")},
1893 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible, but it "
1894 "returns " "\360\235\234\213" " with a better "
1895 "precision.") },
1896 { GNM_FUNC_HELP_EXAMPLES, "=PI()" },
1897 { GNM_FUNC_HELP_SEEALSO, "SQRTPI"},
1898 { GNM_FUNC_HELP_END}
1901 static GnmValue *
1902 gnumeric_pi (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1904 return value_new_float (M_PIgnum);
1907 /***************************************************************************/
1909 static GnmFuncHelp const help_trunc[] = {
1910 { GNM_FUNC_HELP_NAME, F_("TRUNC:@{x} truncated to @{d} digits")},
1911 { GNM_FUNC_HELP_ARG, F_("x:number")},
1912 { GNM_FUNC_HELP_ARG, F_("d:non-negative integer, defaults to 0")},
1913 { GNM_FUNC_HELP_NOTE, F_("If @{d} is omitted or negative then it defaults to zero. If it is not an integer then it is truncated to an integer.")},
1914 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
1915 { GNM_FUNC_HELP_EXAMPLES, "=TRUNC(35.12)"},
1916 { GNM_FUNC_HELP_EXAMPLES, "=TRUNC(43.15,1)"},
1917 { GNM_FUNC_HELP_SEEALSO, "INT"},
1918 { GNM_FUNC_HELP_END}
1921 static GnmValue *
1922 gnumeric_trunc (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1924 gnm_float number = value_get_as_float (argv[0]);
1925 gnm_float digits = argv[1] ? value_get_as_float (argv[1]) : 0;
1927 if (digits >= 0) {
1928 if (digits <= GNM_MAX_EXP) {
1929 gnm_float p10 = gnm_pow10 ((int)digits);
1930 number = gnm_fake_trunc (number * p10) / p10;
1932 } else {
1933 if (digits >= GNM_MIN_EXP) {
1934 /* Keep p10 integer. */
1935 gnm_float p10 = gnm_pow10 ((int)-digits);
1936 number = gnm_fake_trunc (number / p10) * p10;
1937 } else
1938 number = 0;
1941 return value_new_float (number);
1944 /***************************************************************************/
1946 static GnmFuncHelp const help_even[] = {
1947 { GNM_FUNC_HELP_NAME, F_("EVEN:@{x} rounded away from 0 to the next even integer")},
1948 { GNM_FUNC_HELP_ARG, F_("x:number")},
1949 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
1950 { GNM_FUNC_HELP_EXAMPLES, "=EVEN(5.4)"},
1951 { GNM_FUNC_HELP_EXAMPLES, "=EVEN(-5.4)"},
1952 { GNM_FUNC_HELP_SEEALSO, "ODD"},
1953 { GNM_FUNC_HELP_END}
1956 static GnmValue *
1957 gnumeric_even (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1959 gnm_float number, ceiled;
1960 int sign = 1;
1962 number = value_get_as_float (argv[0]);
1963 if (number < 0) {
1964 sign = -1;
1965 number = -number;
1967 ceiled = gnm_ceil (number);
1968 if (gnm_fmod (ceiled, 2) == 0)
1969 if (number > ceiled)
1970 number = sign * (ceiled + 2);
1971 else
1972 number = sign * ceiled;
1973 else
1974 number = sign * (ceiled + 1);
1976 return value_new_float (number);
1979 /***************************************************************************/
1981 static GnmFuncHelp const help_odd[] = {
1982 { GNM_FUNC_HELP_NAME, F_("ODD:@{x} rounded away from 0 to the next odd integer")},
1983 { GNM_FUNC_HELP_ARG, F_("x:number")},
1984 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
1985 { GNM_FUNC_HELP_EXAMPLES, "=ODD(5.4)"},
1986 { GNM_FUNC_HELP_EXAMPLES, "=ODD(-5.4)"},
1987 { GNM_FUNC_HELP_SEEALSO, "EVEN"},
1988 { GNM_FUNC_HELP_END}
1991 static GnmValue *
1992 gnumeric_odd (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1994 gnm_float number, ceiled;
1995 int sign = 1;
1997 number = value_get_as_float (argv[0]);
1998 if (number < 0) {
1999 sign = -1;
2000 number = -number;
2002 ceiled = gnm_ceil (number);
2003 if (gnm_fmod (ceiled, 2) == 1)
2004 if (number > ceiled)
2005 number = sign * (ceiled + 2);
2006 else
2007 number = sign * ceiled;
2008 else
2009 number = sign * (ceiled + 1);
2011 return value_new_float (number);
2014 /***************************************************************************/
2016 static GnmFuncHelp const help_factdouble[] = {
2017 { GNM_FUNC_HELP_NAME, F_("FACTDOUBLE:double factorial")},
2018 { GNM_FUNC_HELP_ARG, F_("x:non-negative integer")},
2019 { GNM_FUNC_HELP_DESCRIPTION, F_("FACTDOUBLE function returns the double factorial @{x}!!")},
2020 { GNM_FUNC_HELP_NOTE, F_("If @{x} is not an integer, it is truncated. If @{x} is negative, FACTDOUBLE returns #NUM!") },
2021 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
2022 { GNM_FUNC_HELP_EXAMPLES, "=FACTDOUBLE(5)"},
2023 { GNM_FUNC_HELP_SEEALSO, "FACT"},
2024 { GNM_FUNC_HELP_END}
2027 static GnmValue *
2028 gnumeric_factdouble (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
2031 gnm_float number = value_get_as_float (argv[0]);
2032 int inumber, n;
2033 gnm_float res;
2035 if (number < 0)
2036 return value_new_error_NUM (ei->pos);
2038 inumber = (int)MIN (number, (gnm_float)INT_MAX);
2039 n = (inumber + 1) / 2;
2041 if (inumber & 1) {
2042 gnm_float lres = gnm_lgamma (n + 0.5) + n * M_LN2gnum;
2043 /* Round as the result ought to be integer. */
2044 res = gnm_floor (0.5 + gnm_exp (lres) / gnm_sqrt (M_PIgnum));
2045 } else
2046 res = gnm_fact (n) * gnm_pow2 (n);
2048 return value_new_float (res);
2051 /***************************************************************************/
2053 static GnmFuncHelp const help_fib[] = {
2054 { GNM_FUNC_HELP_NAME, F_("FIB:Fibonacci numbers")},
2055 { GNM_FUNC_HELP_ARG, F_("n:positive integer")},
2056 { GNM_FUNC_HELP_DESCRIPTION, F_("FIB(@{n}) is the @{n}th Fibonacci number.")},
2057 { GNM_FUNC_HELP_NOTE, F_("If @{n} is not an integer, it is truncated. If it is negative or zero FIB returns #NUM!") },
2058 { GNM_FUNC_HELP_EXAMPLES, "=FIB(23)"},
2059 { GNM_FUNC_HELP_END}
2062 static GnmValue *
2063 gnumeric_fib (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
2066 static int fibs[47];
2067 static int fib_count = G_N_ELEMENTS (fibs);
2068 static gboolean inited = FALSE;
2069 gnm_float n = gnm_floor (value_get_as_float (argv[0]));
2071 if (n <= 0)
2072 return value_new_error_NUM (ei->pos);
2074 if (n < fib_count) {
2075 if (!inited) {
2076 int i;
2077 fibs[1] = fibs[2] = 1;
2078 for (i = 3; i < fib_count; i++)
2079 fibs[i] = fibs[i - 1] + fibs[i - 2];
2080 inited = TRUE;
2082 return value_new_int (fibs[(int)n]);
2083 } else {
2084 gnm_float s5 = gnm_sqrt (5.0);
2085 gnm_float r1 = (1 + s5) / 2;
2086 gnm_float r2 = (1 - s5) / 2;
2087 /* Use the Binet form. */
2088 return value_new_float ((gnm_pow (r1, n) - gnm_pow (r2, n)) / s5);
2092 /***************************************************************************/
2094 static GnmFuncHelp const help_quotient[] = {
2095 { GNM_FUNC_HELP_NAME, F_("QUOTIENT:integer portion of a division")},
2096 { GNM_FUNC_HELP_ARG, F_("numerator:integer")},
2097 { GNM_FUNC_HELP_ARG, F_("denominator:non-zero integer")},
2098 { GNM_FUNC_HELP_DESCRIPTION, F_("QUOTIENT yields the integer portion of the division @{numerator}/@{denominator}.\n"
2099 "QUOTIENT (@{numerator},@{denominator})\xe2\xa8\x89@{denominator}+MOD(@{numerator},@{denominator})=@{numerator}")},
2100 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
2101 { GNM_FUNC_HELP_EXAMPLES, "=QUOTIENT(23,5)"},
2102 { GNM_FUNC_HELP_SEEALSO, "MOD"},
2103 { GNM_FUNC_HELP_END}
2107 static GnmValue *
2108 gnumeric_quotient (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
2110 gnm_float num = value_get_as_float (argv[0]);
2111 gnm_float den = value_get_as_float (argv[1]);
2113 if (den == 0)
2114 return value_new_error_DIV0 (ei->pos);
2115 else
2116 return value_new_float (gnm_trunc (num / den));
2119 /***************************************************************************/
2121 static GnmFuncHelp const help_sign[] = {
2122 { GNM_FUNC_HELP_NAME, F_("SIGN:sign of @{x}")},
2123 { GNM_FUNC_HELP_ARG, F_("x:number")},
2124 { GNM_FUNC_HELP_DESCRIPTION, F_("SIGN returns 1 if the @{x} is positive and it returns -1 if @{x} is negative.")},
2125 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
2126 { GNM_FUNC_HELP_EXAMPLES, "=SIGN(3)"},
2127 { GNM_FUNC_HELP_EXAMPLES, "=SIGN(-3)"},
2128 { GNM_FUNC_HELP_EXAMPLES, "=SIGN(0)"},
2129 { GNM_FUNC_HELP_SEEALSO, "ABS"},
2130 { GNM_FUNC_HELP_END}
2133 static GnmValue *
2134 gnumeric_sign (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
2136 gnm_float n = value_get_as_float (argv[0]);
2138 if (n > 0)
2139 return value_new_int (1);
2140 else if (n == 0)
2141 return value_new_int (0);
2142 else
2143 return value_new_int (-1);
2146 /***************************************************************************/
2148 static GnmFuncHelp const help_sqrtpi[] = {
2149 { GNM_FUNC_HELP_NAME, F_("SQRTPI:the square root of @{x} times "
2150 "\360\235\234\213")},
2151 { GNM_FUNC_HELP_ARG, F_("x:non-negative number")},
2152 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
2153 { GNM_FUNC_HELP_EXAMPLES, "=SQRTPI(2)"},
2154 { GNM_FUNC_HELP_SEEALSO, "PI"},
2155 { GNM_FUNC_HELP_END}
2158 static GnmValue *
2159 gnumeric_sqrtpi (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
2161 gnm_float n = value_get_as_float (argv[0]);
2163 if (n < 0)
2164 return value_new_error_NUM (ei->pos);
2166 return value_new_float (gnm_sqrt (M_PIgnum * n));
2169 /***************************************************************************/
2171 static GnmFuncHelp const help_rounddown[] = {
2172 { GNM_FUNC_HELP_NAME, F_("ROUNDDOWN:@{x} rounded towards 0")},
2173 { GNM_FUNC_HELP_ARG, F_("x:number")},
2174 { GNM_FUNC_HELP_ARG, F_("d:integer, defaults to 0")},
2175 { GNM_FUNC_HELP_DESCRIPTION, F_("If @{d} is greater than zero, @{x} is rounded toward 0 to the given number of digits.\n"
2176 "If @{d} is zero, @{x} is rounded toward 0 to the next integer.\n"
2177 "If @{d} is less than zero, @{x} is rounded toward 0 to the left of the decimal point")},
2178 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
2179 { GNM_FUNC_HELP_EXAMPLES, "=ROUNDDOWN(5.5)"},
2180 { GNM_FUNC_HELP_EXAMPLES, "=ROUNDDOWN(-3.3)"},
2181 { GNM_FUNC_HELP_EXAMPLES, "=ROUNDDOWN(1501.15,1)"},
2182 { GNM_FUNC_HELP_EXAMPLES, "=ROUNDDOWN(1501.15,-2)"},
2183 { GNM_FUNC_HELP_SEEALSO, "ROUND,ROUNDUP"},
2184 { GNM_FUNC_HELP_END}
2187 static GnmValue *
2188 gnumeric_rounddown (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
2190 return gnumeric_trunc (ei, argv);
2193 /***************************************************************************/
2195 static GnmFuncHelp const help_round[] = {
2196 { GNM_FUNC_HELP_NAME, F_("ROUND:rounded @{x}")},
2197 { GNM_FUNC_HELP_ARG, F_("x:number")},
2198 { GNM_FUNC_HELP_ARG, F_("d:integer, defaults to 0")},
2199 { GNM_FUNC_HELP_DESCRIPTION, F_("If @{d} is greater than zero, @{x} is rounded to the given number of digits.\n"
2200 "If @{d} is zero, @{x} is rounded to the next integer.\n"
2201 "If @{d} is less than zero, @{x} is rounded to the left of the decimal point")},
2202 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
2203 { GNM_FUNC_HELP_EXAMPLES, "=ROUND(5.5)"},
2204 { GNM_FUNC_HELP_EXAMPLES, "=ROUND(-3.3)"},
2205 { GNM_FUNC_HELP_EXAMPLES, "=ROUND(1501.15,1)"},
2206 { GNM_FUNC_HELP_EXAMPLES, "=ROUND(1501.15,-2)"},
2207 { GNM_FUNC_HELP_SEEALSO, "ROUNDDOWN,ROUNDUP"},
2208 { GNM_FUNC_HELP_END}
2211 static GnmValue *
2212 gnumeric_round (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
2214 gnm_float number = value_get_as_float (argv[0]);
2215 gnm_float digits = argv[1] ? value_get_as_float (argv[1]) : 0;
2217 if (digits >= 0) {
2218 if (digits <= GNM_MAX_EXP) {
2219 gnm_float p10 = gnm_pow10 ((int)digits);
2220 number = gnm_fake_round (number * p10) / p10;
2222 } else {
2223 if (digits >= GNM_MIN_EXP) {
2224 /* Keep p10 integer. */
2225 gnm_float p10 = gnm_pow10 ((int)-digits);
2226 number = gnm_fake_round (number / p10) * p10;
2227 } else
2228 number = 0;
2231 return value_new_float (number);
2234 /***************************************************************************/
2236 static GnmFuncHelp const help_roundup[] = {
2237 { GNM_FUNC_HELP_NAME, F_("ROUNDUP:@{x} rounded away from 0")},
2238 { GNM_FUNC_HELP_ARG, F_("x:number")},
2239 { GNM_FUNC_HELP_ARG, F_("d:integer, defaults to 0")},
2240 { GNM_FUNC_HELP_DESCRIPTION, F_("If @{d} is greater than zero, @{x} is rounded away from 0 to the given number of digits.\n"
2241 "If @{d} is zero, @{x} is rounded away from 0 to the next integer.\n"
2242 "If @{d} is less than zero, @{x} is rounded away from 0 to the left of the decimal point")},
2243 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
2244 { GNM_FUNC_HELP_EXAMPLES, "=ROUNDUP(5.5)"},
2245 { GNM_FUNC_HELP_EXAMPLES, "=ROUNDUP(-3.3)"},
2246 { GNM_FUNC_HELP_EXAMPLES, "=ROUNDUP(1501.15,1)"},
2247 { GNM_FUNC_HELP_EXAMPLES, "=ROUNDUP(1501.15,-2)"},
2248 { GNM_FUNC_HELP_SEEALSO, "ROUND,ROUNDDOWN,INT"},
2249 { GNM_FUNC_HELP_END}
2252 static gnm_float
2253 gnm_fake_roundup (gnm_float x)
2255 return (x < 0) ? gnm_fake_floor (x) : gnm_fake_ceil (x);
2258 static GnmValue *
2259 gnumeric_roundup (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
2261 gnm_float number = value_get_as_float (argv[0]);
2262 gnm_float digits = argv[1] ? value_get_as_float (argv[1]) : 0;
2264 if (digits >= 0) {
2265 if (digits <= GNM_MAX_EXP) {
2266 gnm_float p10 = gnm_pow10 ((int)digits);
2267 number = gnm_fake_roundup (number * p10) / p10;
2269 } else {
2270 if (digits >= GNM_MIN_EXP) {
2271 /* Keep p10 integer. */
2272 gnm_float p10 = gnm_pow10 ((int)-digits);
2273 number = gnm_fake_roundup (number / p10) * p10;
2274 } else
2275 number = 0;
2278 return value_new_float (number);
2281 /***************************************************************************/
2283 static GnmFuncHelp const help_mround[] = {
2284 { GNM_FUNC_HELP_NAME, F_("MROUND:@{x} rounded to a multiple of @{m}")},
2285 { GNM_FUNC_HELP_ARG, F_("x:number")},
2286 { GNM_FUNC_HELP_ARG, F_("m:number")},
2287 { GNM_FUNC_HELP_NOTE, F_("If @{x} and @{m} have different sign, MROUND returns #NUM!") },
2288 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
2289 { GNM_FUNC_HELP_EXAMPLES, "=MROUND(1.7,0.2)"},
2290 { GNM_FUNC_HELP_EXAMPLES, "=MROUND(321.123,0.12)"},
2291 { GNM_FUNC_HELP_SEEALSO, "ROUNDDOWN,ROUND,ROUNDUP"},
2292 { GNM_FUNC_HELP_END}
2295 static GnmValue *
2296 gnumeric_mround (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
2298 gnm_float const accuracy_limit = 0.0000003;
2299 gnm_float number, multiple;
2300 gnm_float div, mod;
2301 int sign = 1;
2303 number = value_get_as_float (argv[0]);
2304 multiple = value_get_as_float (argv[1]);
2306 /* Weird, but XL compatible. */
2307 if (multiple == 0)
2308 return value_new_int (0);
2310 if ((number > 0 && multiple < 0)
2311 || (number < 0 && multiple > 0))
2312 return value_new_error_NUM (ei->pos);
2314 if (number < 0) {
2315 sign = -1;
2316 number = -number;
2317 multiple = -multiple;
2320 mod = gnm_fmod (number, multiple);
2321 div = number - mod;
2323 return value_new_float (sign * (
2324 div + ((mod + accuracy_limit >= multiple / 2) ? multiple : 0)));
2327 /***************************************************************************/
2329 static GnmFuncHelp const help_arabic[] = {
2330 { GNM_FUNC_HELP_NAME, F_("ARABIC:the Roman numeral @{roman} as number")},
2331 { GNM_FUNC_HELP_ARG, F_("roman:Roman numeral")},
2332 { GNM_FUNC_HELP_DESCRIPTION, F_("Any Roman symbol to the left of a larger symbol "
2333 "(directly or indirectly) reduces the final value "
2334 "by the symbol amount, otherwise, it increases the "
2335 "final amount by the symbol's amount.") },
2336 { GNM_FUNC_HELP_ODF, F_("This function is OpenFormula compatible.")},
2337 { GNM_FUNC_HELP_EXAMPLES, "=ARABIC(\"I\")"},
2338 { GNM_FUNC_HELP_EXAMPLES, "=ARABIC(\"CDLII\")"},
2339 { GNM_FUNC_HELP_EXAMPLES, "=ARABIC(\"MCDXC\")"},
2340 { GNM_FUNC_HELP_EXAMPLES, "=ARABIC(\"MDCCCXCIX\")"},
2341 { GNM_FUNC_HELP_EXAMPLES, "=ARABIC(\"MCMXCIX\")"},
2342 { GNM_FUNC_HELP_EXAMPLES, "=ARABIC(\"mmmcmxcix\")"},
2343 { GNM_FUNC_HELP_EXAMPLES, "=ARABIC(\"MIM\")"},
2344 { GNM_FUNC_HELP_EXAMPLES, "=ARABIC(\"IVM\")"},
2345 { GNM_FUNC_HELP_SEEALSO, "ROMAN"},
2346 { GNM_FUNC_HELP_END}
2349 static GnmValue *
2350 gnumeric_arabic (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
2352 const gchar *roman = (const gchar *)value_peek_string (argv[0]);
2353 int slen = strlen (roman);
2354 int last = 0;
2355 int result = 0;
2356 gchar *this = (gchar *)(roman + slen);
2358 while (this > roman) {
2359 int this_val = 0;
2360 this = g_utf8_prev_char (this);
2361 switch (*this) {
2362 case 'i':
2363 case 'I':
2364 this_val = 1;
2365 break;
2366 case 'v':
2367 case 'V':
2368 this_val = 5;
2369 break;
2370 case 'x':
2371 case 'X':
2372 this_val = 10;
2373 break;
2374 case 'l':
2375 case 'L':
2376 this_val = 50;
2377 break;
2378 case 'c':
2379 case 'C':
2380 this_val = 100;
2381 break;
2382 case 'd':
2383 case 'D':
2384 this_val = 500;
2385 break;
2386 case 'm':
2387 case 'M':
2388 this_val = 1000;
2389 break;
2390 default:
2391 break;
2393 if (this_val > 0) {
2394 if (this_val < last)
2395 result -= this_val;
2396 else {
2397 result += this_val;
2398 last = this_val;
2402 return value_new_int (result);
2405 /***************************************************************************/
2407 static GnmFuncHelp const help_roman[] = {
2408 { GNM_FUNC_HELP_NAME, F_("ROMAN:@{n} as a roman numeral text")},
2409 { GNM_FUNC_HELP_ARG, F_("n:non-negative integer")},
2410 { GNM_FUNC_HELP_ARG, F_("type:0,1,2,3,or 4, defaults to 0")},
2411 { GNM_FUNC_HELP_DESCRIPTION, F_("ROMAN returns the arabic number @{n} as a roman numeral text.\n"
2412 "If @{type} is 0 or it is omitted, ROMAN returns classic roman numbers.\n"
2413 "Type 1 is more concise than classic type, type 2 is more concise than "
2414 "type 1, and type 3 is more concise than type 2. Type 4 is a simplified type.")},
2415 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
2416 { GNM_FUNC_HELP_EXAMPLES, "=ROMAN(999)"},
2417 { GNM_FUNC_HELP_EXAMPLES, "=ROMAN(999,1)"},
2418 { GNM_FUNC_HELP_EXAMPLES, "=ROMAN(999,2)"},
2419 { GNM_FUNC_HELP_EXAMPLES, "=ROMAN(999,3)"},
2420 { GNM_FUNC_HELP_EXAMPLES, "=ROMAN(999,4)"},
2421 { GNM_FUNC_HELP_END}
2424 static GnmValue *
2425 gnumeric_roman (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
2427 static char const letter[] = { 'M', 'D', 'C', 'L', 'X', 'V', 'I' };
2428 int const largest = 1000;
2429 char buf[256];
2430 char *p;
2431 gnm_float n = gnm_floor (value_get_as_float (argv[0]));
2432 gnm_float form = argv[1] ? gnm_floor (value_get_as_float (argv[1])) : 0;
2433 int i, j, dec;
2435 dec = largest;
2437 if (n < 0 || n > 3999)
2438 return value_new_error_VALUE (ei->pos);
2439 if (form < 0 || form > 4)
2440 return value_new_error_VALUE (ei->pos);
2442 if (n == 0)
2443 return value_new_string ("");
2445 for (i = j = 0; dec > 1; dec /= 10, j += 2) {
2446 for (; n > 0; i++) {
2447 if (n >= dec) {
2448 buf[i] = letter[j];
2449 n -= dec;
2450 } else if (n >= dec - dec / 10) {
2451 buf[i++] = letter[j + 2];
2452 buf[i] = letter[j];
2453 n -= dec - dec / 10;
2454 } else if (n >= dec / 2) {
2455 buf[i] = letter[j + 1];
2456 n -= dec / 2;
2457 } else if (n >= dec / 2 - dec / 10) {
2458 buf[i++] = letter[j + 2];
2459 buf[i] = letter[j + 1];
2460 n -= dec / 2 - dec / 10;
2461 } else if (dec == 10) {
2462 buf[i] = letter[j + 2];
2463 n--;
2464 } else
2465 break;
2468 buf[i] = '\0';
2471 if (form > 0) {
2472 /* Replace ``XLV'' with ``VL'' */
2473 if ((p = strstr (buf, "XLV")) != NULL) {
2474 *p++ = 'V';
2475 *p++ = 'L';
2476 for ( ; *p; p++)
2477 *p = *(p+1);
2479 /* Replace ``XCV'' with ``VC'' */
2480 if ((p = strstr (buf, "XCV")) != NULL) {
2481 *p++ = 'V';
2482 *p++ = 'C';
2483 for ( ; *p; p++)
2484 *p = *(p+1);
2486 /* Replace ``CDL'' with ``LD'' */
2487 if ((p = strstr (buf, "CDL")) != NULL) {
2488 *p++ = 'L';
2489 *p++ = 'D';
2490 for ( ; *p; p++)
2491 *p = *(p+1);
2493 /* Replace ``CML'' with ``LM'' */
2494 if ((p = strstr (buf, "CML")) != NULL) {
2495 *p++ = 'L';
2496 *p++ = 'M';
2497 for ( ; *p; p++)
2498 *p = *(p+1);
2500 /* Replace ``CMVC'' with ``LMVL'' */
2501 if ((p = strstr (buf, "CMVC")) != NULL) {
2502 *p++ = 'L';
2503 *p++ = 'M';
2504 *p++ = 'V';
2505 *p++ = 'L';
2508 if (form == 1) {
2509 /* Replace ``CDXC'' with ``LDXL'' */
2510 if ((p = strstr (buf, "CDXC")) != NULL) {
2511 *p++ = 'L';
2512 *p++ = 'D';
2513 *p++ = 'X';
2514 *p++ = 'L';
2516 /* Replace ``CDVC'' with ``LDVL'' */
2517 if ((p = strstr (buf, "CDVC")) != NULL) {
2518 *p++ = 'L';
2519 *p++ = 'D';
2520 *p++ = 'V';
2521 *p++ = 'L';
2523 /* Replace ``CMXC'' with ``LMXL'' */
2524 if ((p = strstr (buf, "CMXC")) != NULL) {
2525 *p++ = 'L';
2526 *p++ = 'M';
2527 *p++ = 'X';
2528 *p++ = 'L';
2530 /* Replace ``XCIX'' with ``VCIV'' */
2531 if ((p = strstr (buf, "XCIX")) != NULL) {
2532 *p++ = 'V';
2533 *p++ = 'C';
2534 *p++ = 'I';
2535 *p++ = 'V';
2537 /* Replace ``XLIX'' with ``VLIV'' */
2538 if ((p = strstr (buf, "XLIX")) != NULL) {
2539 *p++ = 'V';
2540 *p++ = 'L';
2541 *p++ = 'I';
2542 *p++ = 'V';
2545 if (form > 1) {
2546 /* Replace ``XLIX'' with ``IL'' */
2547 if ((p = strstr (buf, "XLIX")) != NULL) {
2548 *p++ = 'I';
2549 *p++ = 'L';
2550 for ( ; *p; p++)
2551 *p = *(p+2);
2553 /* Replace ``XCIX'' with ``IC'' */
2554 if ((p = strstr (buf, "XCIX")) != NULL) {
2555 *p++ = 'I';
2556 *p++ = 'C';
2557 for ( ; *p; p++)
2558 *p = *(p+2);
2560 /* Replace ``CDXC'' with ``XD'' */
2561 if ((p = strstr (buf, "CDXC")) != NULL) {
2562 *p++ = 'X';
2563 *p++ = 'D';
2564 for ( ; *p; p++)
2565 *p = *(p+2);
2567 /* Replace ``CDVC'' with ``XDV'' */
2568 if ((p = strstr (buf, "CDVC")) != NULL) {
2569 *p++ = 'X';
2570 *p++ = 'D';
2571 *p++ = 'V';
2572 for ( ; *p; p++)
2573 *p = *(p+1);
2575 /* Replace ``CDIC'' with ``XDIX'' */
2576 if ((p = strstr (buf, "CDIC")) != NULL) {
2577 *p++ = 'X';
2578 *p++ = 'D';
2579 *p++ = 'I';
2580 *p++ = 'X';
2582 /* Replace ``LMVL'' with ``XMV'' */
2583 if ((p = strstr (buf, "LMVL")) != NULL) {
2584 *p++ = 'X';
2585 *p++ = 'M';
2586 *p++ = 'V';
2587 for ( ; *p; p++)
2588 *p = *(p+1);
2590 /* Replace ``CMIC'' with ``XMIX'' */
2591 if ((p = strstr (buf, "CMIC")) != NULL) {
2592 *p++ = 'X';
2593 *p++ = 'M';
2594 *p++ = 'I';
2595 *p++ = 'X';
2597 /* Replace ``CMXC'' with ``XM'' */
2598 if ((p = strstr (buf, "CMXC")) != NULL) {
2599 *p++ = 'X';
2600 *p++ = 'M';
2601 for ( ; *p; p++)
2602 *p = *(p+2);
2605 if (form > 2) {
2606 /* Replace ``XDV'' with ``VD'' */
2607 if ((p = strstr (buf, "XDV")) != NULL) {
2608 *p++ = 'V';
2609 *p++ = 'D';
2610 for ( ; *p; p++)
2611 *p = *(p+1);
2613 /* Replace ``XDIX'' with ``VDIV'' */
2614 if ((p = strstr (buf, "XDIX")) != NULL) {
2615 *p++ = 'V';
2616 *p++ = 'D';
2617 *p++ = 'I';
2618 *p++ = 'V';
2620 /* Replace ``XMV'' with ``VM'' */
2621 if ((p = strstr (buf, "XMV")) != NULL) {
2622 *p++ = 'V';
2623 *p++ = 'M';
2624 for ( ; *p; p++)
2625 *p = *(p+1);
2627 /* Replace ``XMIX'' with ``VMIV'' */
2628 if ((p = strstr (buf, "XMIX")) != NULL) {
2629 *p++ = 'V';
2630 *p++ = 'M';
2631 *p++ = 'I';
2632 *p++ = 'V';
2635 if (form == 4) {
2636 /* Replace ``VDIV'' with ``ID'' */
2637 if ((p = strstr (buf, "VDIV")) != NULL) {
2638 *p++ = 'I';
2639 *p++ = 'D';
2640 for ( ; *p; p++)
2641 *p = *(p+2);
2643 /* Replace ``VMIV'' with ``IM'' */
2644 if ((p = strstr (buf, "VMIV")) != NULL) {
2645 *p++ = 'I';
2646 *p++ = 'M';
2647 for ( ; *p; p++)
2648 *p = *(p+2);
2652 return value_new_string (buf);
2655 /***************************************************************************/
2657 static GnmFuncHelp const help_sumx2my2[] = {
2658 { GNM_FUNC_HELP_NAME, F_("SUMX2MY2:sum of the difference of squares")},
2659 { GNM_FUNC_HELP_ARG, F_("array0:first cell area")},
2660 { GNM_FUNC_HELP_ARG, F_("array1:second cell area")},
2661 { GNM_FUNC_HELP_DESCRIPTION, F_("SUMX2MY2 function returns the sum of the difference of squares of "
2662 "corresponding values in two arrays. The equation of SUMX2MY2 is SUM(x^2-y^2).")},
2663 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
2664 { GNM_FUNC_HELP_EXAMPLES, F_("Let us assume that the cells A1, A2, ..., A5 contain numbers 11, 15, 17, 21, and 43 and the cells B1, B2, ..., B5 hold numbers 13, 22, 31, 33, and 39.") },
2665 { GNM_FUNC_HELP_EXAMPLES, F_("Then SUMX2MY2(A1:A5,B1:B5) yields -1299.")},
2666 { GNM_FUNC_HELP_SEEALSO, "SUMSQ,SUMX2PY2"},
2667 { GNM_FUNC_HELP_END}
2670 static int
2671 gnm_range_sumx2my2 (gnm_float const *xs, const gnm_float *ys,
2672 int n, gnm_float *res)
2674 gnm_float s = 0;
2675 int i;
2677 for (i = 0; i < n; i++)
2678 s += xs[i] * xs[i] - ys[i] * ys[i];
2680 *res = s;
2681 return 0;
2685 static GnmValue *
2686 gnumeric_sumx2my2 (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
2688 return float_range_function2 (argv[0], argv[1],
2690 gnm_range_sumx2my2,
2691 COLLECT_IGNORE_BLANKS |
2692 COLLECT_IGNORE_STRINGS |
2693 COLLECT_IGNORE_BOOLS,
2694 GNM_ERROR_VALUE);
2697 /***************************************************************************/
2699 static GnmFuncHelp const help_sumx2py2[] = {
2700 { GNM_FUNC_HELP_NAME, F_("SUMX2PY2:sum of the sum of squares")},
2701 { GNM_FUNC_HELP_ARG, F_("array0:first cell area")},
2702 { GNM_FUNC_HELP_ARG, F_("array1:second cell area")},
2703 { GNM_FUNC_HELP_DESCRIPTION, F_("SUMX2PY2 function returns the sum of the sum of squares of "
2704 "corresponding values in two arrays. The equation of SUMX2PY2 is SUM(x^2+y^2).")},
2705 { GNM_FUNC_HELP_NOTE, F_("If @{array0} and @{array1} have different number of data points, SUMX2PY2 returns #N/A.\n"
2706 "Strings and empty cells are simply ignored.") },
2707 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
2708 { GNM_FUNC_HELP_EXAMPLES, F_("Let us assume that the cells A1, A2, ..., A5 contain numbers 11, 15, 17, 21, and 43 and the cells B1, B2, ..., B5 hold numbers 13, 22, 31, 33, and 39.") },
2709 { GNM_FUNC_HELP_EXAMPLES, F_("Then SUMX2PY2(A1:A5,B1:B5) yields 7149.") },
2710 { GNM_FUNC_HELP_SEEALSO, "SUMSQ,SUMX2MY2"},
2711 { GNM_FUNC_HELP_END}
2714 static int
2715 gnm_range_sumx2py2 (gnm_float const *xs, const gnm_float *ys,
2716 int n, gnm_float *res)
2718 gnm_float s = 0;
2719 int i;
2721 for (i = 0; i < n; i++)
2722 s += xs[i] * xs[i] + ys[i] * ys[i];
2724 *res = s;
2725 return 0;
2728 static GnmValue *
2729 gnumeric_sumx2py2 (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
2731 return float_range_function2 (argv[0], argv[1],
2733 gnm_range_sumx2py2,
2734 COLLECT_IGNORE_BLANKS |
2735 COLLECT_IGNORE_STRINGS |
2736 COLLECT_IGNORE_BOOLS,
2737 GNM_ERROR_VALUE);
2740 /***************************************************************************/
2742 static GnmFuncHelp const help_sumxmy2[] = {
2743 { GNM_FUNC_HELP_NAME, F_("SUMXMY2:sum of the squares of differences")},
2744 { GNM_FUNC_HELP_ARG, F_("array0:first cell area")},
2745 { GNM_FUNC_HELP_ARG, F_("array1:second cell area")},
2746 { GNM_FUNC_HELP_DESCRIPTION, F_("SUMXMY2 function returns the sum of the squares of the differences of "
2747 "corresponding values in two arrays. The equation of SUMXMY2 is SUM((x-y)^2).")},
2748 { GNM_FUNC_HELP_NOTE, F_("If @{array0} and @{array1} have different number of data points, SUMXMY2 returns #N/A.\n"
2749 "Strings and empty cells are simply ignored.") },
2750 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
2751 { GNM_FUNC_HELP_EXAMPLES, F_("Let us assume that the cells A1, A2, ..., A5 contain numbers 11, 15, 17, 21, and 43 and the cells B1, B2, ..., B5 hold numbers 13, 22, 31, 33, and 39.") },
2752 { GNM_FUNC_HELP_EXAMPLES, F_("Then SUMXMY2(A1:A5,B1:B5) yields 409.") },
2753 { GNM_FUNC_HELP_SEEALSO, "SUMSQ,SUMX2MY2,SUMX2PY2"},
2754 { GNM_FUNC_HELP_END}
2757 static int
2758 gnm_range_sumxmy2 (gnm_float const *xs, const gnm_float *ys,
2759 int n, gnm_float *res)
2761 gnm_float s = 0;
2762 int i;
2764 for (i = 0; i < n; i++) {
2765 gnm_float d = (xs[i] - ys[i]);
2766 s += d * d;
2769 *res = s;
2770 return 0;
2773 static GnmValue *
2774 gnumeric_sumxmy2 (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
2776 return float_range_function2 (argv[0], argv[1],
2778 gnm_range_sumxmy2,
2779 COLLECT_IGNORE_BLANKS |
2780 COLLECT_IGNORE_STRINGS |
2781 COLLECT_IGNORE_BOOLS,
2782 GNM_ERROR_VALUE);
2785 /***************************************************************************/
2787 static GnmFuncHelp const help_seriessum[] = {
2788 { GNM_FUNC_HELP_NAME, F_("SERIESSUM:sum of a power series at @{x}")},
2789 { GNM_FUNC_HELP_ARG, F_("x:number where to evaluate the power series")},
2790 { GNM_FUNC_HELP_ARG, F_("n:non-negative integer, exponent of the lowest term of the series")},
2791 { GNM_FUNC_HELP_ARG, F_("m:increment to each exponent")},
2792 { GNM_FUNC_HELP_ARG, F_("coeff:coefficients of the power series")},
2793 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
2794 { GNM_FUNC_HELP_EXAMPLES, F_("Let us assume that the cells A1, A2, ..., A5 contain numbers 1.23, 2.32, 2.98, 3.42, and 4.33.") },
2795 { GNM_FUNC_HELP_EXAMPLES, F_("Then SERIESSUM(2,1,2.23,A1:A5) evaluates as 5056.37439843926") },
2796 { GNM_FUNC_HELP_SEEALSO, "COUNT,SUM"},
2797 { GNM_FUNC_HELP_END}
2800 static GnmValue *
2801 gnumeric_seriessum (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
2803 gnm_float x = value_get_as_float (argv[0]);
2804 gnm_float n = value_get_as_float (argv[1]);
2805 gnm_float m = value_get_as_float (argv[2]);
2806 GnmValue *result = NULL;
2807 int N;
2808 /* Ignore blanks; err on bools or strings. */
2809 gnm_float *data =
2810 collect_floats_value (argv[3], ei->pos,
2811 COLLECT_IGNORE_BLANKS, &N, &result);
2813 if (result)
2814 goto done;
2816 if (x == 0) {
2817 if (n <= 0 || n + (N - 1) * m <= 0)
2818 result = value_new_error_NUM (ei->pos);
2819 else
2820 result = value_new_float (0);
2821 } else {
2822 gnm_float x_m = gnm_pow (x, m);
2823 gnm_float sum = 0;
2824 int i;
2825 x = gnm_pow (x, n);
2827 for (i = 0; i < N; i++) {
2828 sum += data[i] * x;
2829 x *= x_m;
2832 if (gnm_finite (sum))
2833 result = value_new_float (sum);
2834 else
2835 result = value_new_error_NUM (ei->pos);
2838 done:
2839 g_free (data);
2840 return result;
2843 /***************************************************************************/
2845 static GnmFuncHelp const help_minverse[] = {
2846 { GNM_FUNC_HELP_NAME, F_("MINVERSE:the inverse matrix of @{matrix}")},
2847 { GNM_FUNC_HELP_ARG, F_("matrix:a square matrix")},
2848 { GNM_FUNC_HELP_NOTE, F_("If @{matrix} is not invertible, MINVERSE returns #NUM!") },
2849 { GNM_FUNC_HELP_NOTE, F_("If @{matrix} does not contain an equal number of columns and rows, MINVERSE returns #VALUE!") },
2850 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
2851 { GNM_FUNC_HELP_SEEALSO, "MMULT,MDETERM,LINSOLVE"},
2852 { GNM_FUNC_HELP_END}
2856 static GnmValue *
2857 gnumeric_minverse (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
2859 GnmMatrix *A = NULL;
2860 GnmValue *res = NULL;
2862 A = gnm_matrix_from_value (argv[0], &res, ei->pos);
2863 if (!A) goto out;
2865 if (A->cols != A->rows || gnm_matrix_is_empty (A)) {
2866 res = value_new_error_VALUE (ei->pos);
2867 goto out;
2870 if (gnm_matrix_invert (A->data, A->rows))
2871 res = gnm_matrix_to_value (A);
2872 else
2873 res = value_new_error_NUM (ei->pos);
2875 out:
2876 if (A) gnm_matrix_unref (A);
2877 return res;
2880 /***************************************************************************/
2882 static GnmFuncHelp const help_mpseudoinverse[] = {
2883 { GNM_FUNC_HELP_NAME, F_("MPSEUDOINVERSE:the pseudo-inverse matrix of @{matrix}")},
2884 { GNM_FUNC_HELP_ARG, F_("matrix:a matrix")},
2885 { GNM_FUNC_HELP_ARG, F_("threshold:a relative size threshold for discarding eigenvalues")},
2886 { GNM_FUNC_HELP_SEEALSO, "MINVERSE"},
2887 { GNM_FUNC_HELP_END}
2891 static GnmValue *
2892 gnumeric_mpseudoinverse (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
2894 GnmMatrix *A = NULL;
2895 GnmMatrix *B = NULL;
2896 GnmValue *res = NULL;
2897 gnm_float threshold = argv[1] ? value_get_as_float (argv[1]) : 256 * GNM_EPSILON;
2899 A = gnm_matrix_from_value (argv[0], &res, ei->pos);
2900 if (!A) goto out;
2902 if (gnm_matrix_is_empty (A)) {
2903 res = value_new_error_VALUE (ei->pos);
2904 goto out;
2907 B = gnm_matrix_new (A->cols, A->rows); /* Shape of A^t */
2908 gnm_matrix_pseudo_inverse (A->data, A->rows, A->cols, threshold, B->data);
2909 res = gnm_matrix_to_value (B);
2911 out:
2912 if (A) gnm_matrix_unref (A);
2913 if (B) gnm_matrix_unref (B);
2914 return res;
2917 /***************************************************************************/
2919 static GnmFuncHelp const help_cholesky[] = {
2920 { GNM_FUNC_HELP_NAME, F_("CHOLESKY:the Cholesky decomposition of the symmetric positive-definite @{matrix}")},
2921 { GNM_FUNC_HELP_ARG, F_("matrix:a symmetric positive definite matrix")},
2922 { GNM_FUNC_HELP_NOTE, F_("If the Cholesky-Banachiewicz algorithm applied to @{matrix} fails, Cholesky returns #NUM!") },
2923 { GNM_FUNC_HELP_NOTE, F_("If @{matrix} does not contain an equal number of columns and rows, CHOLESKY returns #VALUE!") },
2924 { GNM_FUNC_HELP_SEEALSO, "MINVERSE,MMULT,MDETERM"},
2925 { GNM_FUNC_HELP_END}
2928 static gboolean
2929 gnm_matrix_cholesky (GnmMatrix const *A, GnmMatrix *B)
2931 int r, c, k;
2932 gnm_float sum;
2933 int n = A->cols;
2935 for (r = 0; r < n; r++) {
2936 for (c = 0; c < r; c++) {
2937 sum = 0.;
2938 for (k = 0; k < c; k++)
2939 sum += B->data[r][k] * B->data[c][k];
2940 B->data[c][r] = 0;
2941 B->data[r][c] = (A->data[r][c] - sum) / B->data[c][c];
2943 sum = 0;
2944 for (k = 0; k < r; k++)
2945 sum += B->data[r][k] * B->data[r][k];
2946 B->data[r][r] = gnm_sqrt (A->data[r][r] - sum);
2948 return TRUE;
2951 static void
2952 make_symmetric (GnmMatrix *m)
2954 int c, r;
2956 g_return_if_fail (m->cols == m->rows);
2958 for (c = 0; c < m->cols; ++c) {
2959 for (r = c + 1; r < m->rows; ++r) {
2960 gnm_float a = (m->data[r][c] + m->data[c][r]) / 2;
2961 m->data[r][c] = m->data[c][r] = a;
2966 static GnmValue *
2967 gnumeric_cholesky (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
2969 GnmMatrix *A = NULL;
2970 GnmMatrix *B = NULL;
2971 GnmValue *res = NULL;
2973 A = gnm_matrix_from_value (argv[0], &res, ei->pos);
2974 if (!A) goto out;
2976 if (A->cols != A->rows || gnm_matrix_is_empty (A)) {
2977 res = value_new_error_VALUE (ei->pos);
2978 goto out;
2980 make_symmetric (A);
2982 B = gnm_matrix_new (A->rows, A->cols);
2984 if (gnm_matrix_cholesky (A, B))
2985 res = gnm_matrix_to_value (B);
2986 else
2987 res = value_new_error_NUM (ei->pos);
2989 out:
2990 if (A) gnm_matrix_unref (A);
2991 if (B) gnm_matrix_unref (B);
2992 return res;
2995 /***************************************************************************/
2997 static GnmFuncHelp const help_munit[] = {
2998 { GNM_FUNC_HELP_NAME, F_("MUNIT:the @{n} by @{n} identity matrix")},
2999 { GNM_FUNC_HELP_ARG, F_("n:size of the matrix")},
3000 { GNM_FUNC_HELP_ODF, F_("This function is OpenFormula compatible.")},
3001 { GNM_FUNC_HELP_SEEALSO, "MMULT,MDETERM,MINVERSE"},
3002 { GNM_FUNC_HELP_END}
3005 static GnmValue *
3006 gnumeric_munit (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
3008 gnm_float n = value_get_as_float (argv[0]);
3009 gint c, ni;
3010 GnmValue *res;
3012 if (n < 1)
3013 return value_new_error_NUM (ei->pos);
3016 * This provides some protection against bogus sizes and
3017 * running out of memory.
3019 if (n * n >= G_MAXINT ||
3020 n > 5000) /* Arbitrary */
3021 return value_new_error_NUM (ei->pos);
3023 ni = (int)n;
3024 res = value_new_array (ni, ni);
3025 for (c = 0; c < ni; ++c) {
3026 value_release (res->v_array.vals[c][c]);
3027 res->v_array.vals[c][c] = value_new_int (1);
3030 return res;
3033 /***************************************************************************/
3035 static GnmFuncHelp const help_mmult[] = {
3036 { GNM_FUNC_HELP_NAME, F_("MMULT:the matrix product of @{mat1} and @{mat2}")},
3037 { GNM_FUNC_HELP_ARG, F_("mat1:a matrix")},
3038 { GNM_FUNC_HELP_ARG, F_("mat2:a matrix")},
3039 { GNM_FUNC_HELP_NOTE, F_("The number of columns in @{mat1} must equal the number of rows in @{mat2}; otherwise #VALUE! is returned. The result of MMULT is an array, in which the number of rows is the same as in @{mat1}), and the number of columns is the same as in (@{mat2}).") },
3040 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
3041 { GNM_FUNC_HELP_SEEALSO, "TRANSPOSE,MINVERSE"},
3042 { GNM_FUNC_HELP_END}
3046 static GnmValue *
3047 gnumeric_mmult (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
3049 GnmMatrix *A = NULL;
3050 GnmMatrix *B = NULL;
3051 GnmMatrix *C = NULL;
3052 GnmValue *res = NULL;
3054 A = gnm_matrix_from_value (argv[0], &res, ei->pos);
3055 if (!A) goto out;
3057 B = gnm_matrix_from_value (argv[1], &res, ei->pos);
3058 if (!B) goto out;
3060 if (A->cols != B->rows || gnm_matrix_is_empty (A) || gnm_matrix_is_empty (B)) {
3061 res = value_new_error_VALUE (ei->pos);
3062 goto out;
3065 C = gnm_matrix_new (A->rows, B->cols);
3066 gnm_matrix_multiply (C, A, B);
3067 res = gnm_matrix_to_value (C);
3069 out:
3070 if (A) gnm_matrix_unref (A);
3071 if (B) gnm_matrix_unref (B);
3072 if (C) gnm_matrix_unref (C);
3073 return res;
3076 /***************************************************************************/
3078 static GnmFuncHelp const help_linsolve[] = {
3079 { GNM_FUNC_HELP_NAME, F_("LINSOLVE:solve linear equation")},
3080 { GNM_FUNC_HELP_ARG, F_("A:a matrix")},
3081 { GNM_FUNC_HELP_ARG, F_("B:a matrix")},
3082 { GNM_FUNC_HELP_DESCRIPTION,
3083 F_("Solves the equation @{A}*X=@{B} and returns X.") },
3084 { GNM_FUNC_HELP_NOTE, F_("If the matrix @{A} is singular, #VALUE! is returned.") },
3085 { GNM_FUNC_HELP_SEEALSO, "MINVERSE"},
3086 { GNM_FUNC_HELP_END}
3090 static GnmValue *
3091 gnumeric_linsolve (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
3093 GnmMatrix *A = NULL;
3094 GnmMatrix *B = NULL;
3095 GnmValue *res = NULL;
3096 GORegressionResult regres;
3098 A = gnm_matrix_from_value (argv[0], &res, ei->pos);
3099 if (!A) goto out;
3101 B = gnm_matrix_from_value (argv[1], &res, ei->pos);
3102 if (!B) goto out;
3104 if (A->cols != A->rows || gnm_matrix_is_empty (A) ||
3105 B->rows != A->rows || gnm_matrix_is_empty (B)) {
3106 res = value_new_error_VALUE (ei->pos);
3107 goto out;
3110 regres = gnm_linear_solve_multiple (A, B);
3112 if (regres != GO_REG_ok && regres != GO_REG_near_singular_good) {
3113 res = value_new_error_NUM (ei->pos);
3114 } else {
3115 int c, r;
3117 res = value_new_array_non_init (B->cols, B->rows);
3118 for (c = 0; c < B->cols; c++) {
3119 res->v_array.vals[c] = g_new (GnmValue *, B->rows);
3120 for (r = 0; r < B->rows; r++)
3121 res->v_array.vals[c][r] =
3122 value_new_float (B->data[r][c]);
3126 out:
3127 if (A) gnm_matrix_unref (A);
3128 if (B) gnm_matrix_unref (B);
3129 return res;
3132 /***************************************************************************/
3134 static GnmFuncHelp const help_mdeterm[] = {
3135 { GNM_FUNC_HELP_NAME, F_("MDETERM:the determinant of the matrix @{matrix}")},
3136 { GNM_FUNC_HELP_ARG, F_("matrix:a square matrix")},
3137 { GNM_FUNC_HELP_EXAMPLES, F_("Let us assume that A1,...,A4 contain numbers 2, 3, 7, and 3; B1,..., B4 4, 2, 4, and 1; C1,...,C4 9, 4, 3; and 2; and D1,...,D4 7, 3, 6, and 5. Then MDETERM(A1:D4) yields 148.")},
3138 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
3139 { GNM_FUNC_HELP_SEEALSO, "MMULT,MINVERSE"},
3140 { GNM_FUNC_HELP_END}
3143 static GnmValue *
3144 gnumeric_mdeterm (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
3146 GnmMatrix *A = NULL;
3147 GnmValue *res = NULL;
3149 A = gnm_matrix_from_value (argv[0], &res, ei->pos);
3150 if (!A) goto out;
3152 if (A->cols != A->rows || gnm_matrix_is_empty (A)) {
3153 res = value_new_error_VALUE (ei->pos);
3154 goto out;
3157 res = value_new_float (gnm_matrix_determinant (A->data, A->rows));
3159 out:
3160 if (A) gnm_matrix_unref (A);
3161 return res;
3164 /***************************************************************************/
3166 static GnmFuncHelp const help_sumproduct[] = {
3167 { GNM_FUNC_HELP_NAME, F_("SUMPRODUCT:multiplies components and adds the results") },
3168 { GNM_FUNC_HELP_DESCRIPTION,
3169 F_("Multiplies corresponding data entries in the "
3170 "given arrays or ranges, and then returns the sum of those "
3171 "products.") },
3172 { GNM_FUNC_HELP_NOTE, F_("If an entry is not numeric, the value zero is used instead.") },
3173 { GNM_FUNC_HELP_NOTE, F_("If arrays or range arguments do not have the same dimensions, "
3174 "return #VALUE! error.") },
3175 { GNM_FUNC_HELP_NOTE, F_("This function ignores logicals, so using SUMPRODUCT(A1:A5>0) will not work. Instead use SUMPRODUCT(--(A1:A5>0))") },
3176 #if 0
3177 "@EXAMPLES=\n"
3178 "Let us assume that the cells A1, A2, ..., A5 contain numbers "
3179 "11, 15, 17, 21, and 43 and the cells B1, B2, ..., B5 hold "
3180 "numbers 13, 22, 31, 33, and 39. Then\n"
3181 "SUMPRODUCT(A1:A5,B1:B5) equals 3370.\n"
3182 #endif
3183 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
3184 { GNM_FUNC_HELP_ODF, F_("This function is not OpenFormula compatible. Use ODF.SUMPRODUCT instead.") },
3185 { GNM_FUNC_HELP_SEEALSO, "SUM,PRODUCT,G_PRODUCT,ODF.SUMPRODUCT" },
3186 { GNM_FUNC_HELP_END }
3189 static GnmFuncHelp const help_odf_sumproduct[] = {
3190 { GNM_FUNC_HELP_NAME, F_("ODF.SUMPRODUCT:multiplies components and adds the results") },
3191 { GNM_FUNC_HELP_DESCRIPTION,
3192 F_("Multiplies corresponding data entries in the "
3193 "given arrays or ranges, and then returns the sum of those "
3194 "products.") },
3195 { GNM_FUNC_HELP_NOTE, F_("If an entry is not numeric or logical, the value zero is used instead.") },
3196 { GNM_FUNC_HELP_NOTE, F_("If arrays or range arguments do not have the same dimensions, "
3197 "return #VALUE! error.") },
3198 { GNM_FUNC_HELP_NOTE, F_("This function differs from SUMPRODUCT by considering booleans.") },
3199 { GNM_FUNC_HELP_EXCEL, F_("This function is not Excel compatible. Use SUMPRODUCT instead.") },
3200 { GNM_FUNC_HELP_ODF, F_("This function is OpenFormula compatible.") },
3201 { GNM_FUNC_HELP_SEEALSO, "SUMPRODUCT,SUM,PRODUCT,G_PRODUCT" },
3202 { GNM_FUNC_HELP_END }
3205 static GnmValue *
3206 gnumeric_sumproduct_common (gboolean ignore_bools, GnmFuncEvalInfo *ei,
3207 int argc, GnmExprConstPtr const *argv)
3209 gnm_float **data;
3210 GnmValue *result;
3211 int i;
3212 gboolean size_error = FALSE;
3213 int sizex = -1, sizey = -1;
3215 if (argc == 0)
3216 return value_new_error_VALUE (ei->pos);
3218 data = g_new0 (gnm_float *, argc);
3220 for (i = 0; i < argc; i++) {
3221 int thissizex, thissizey, x, y;
3222 GnmExpr const *expr = argv[i];
3223 GnmValue *val = gnm_expr_eval
3224 (expr, ei->pos,
3225 GNM_EXPR_EVAL_PERMIT_NON_SCALAR |
3226 GNM_EXPR_EVAL_PERMIT_EMPTY);
3228 if (!val) {
3229 size_error = TRUE;
3230 break;
3233 thissizex = value_area_get_width (val, ei->pos);
3234 thissizey = value_area_get_height (val, ei->pos);
3236 if (i == 0) {
3237 sizex = thissizex;
3238 sizey = thissizey;
3239 } else if (sizex != thissizex || sizey != thissizey)
3240 size_error = TRUE;
3242 data[i] = g_new (gnm_float, thissizex * thissizey);
3243 for (y = 0; y < thissizey; y++) {
3244 for (x = 0; x < thissizex; x++) {
3245 /* FIXME: efficiency worries? */
3246 GnmValue const *v = value_area_fetch_x_y (val, x, y, ei->pos);
3247 switch (v->v_any.type) {
3248 case VALUE_ERROR:
3250 * We carefully tranverse the argument
3251 * list and then the arrays in such an
3252 * order that the first error we see is
3253 * the final result.
3255 * args: left-to-right.
3256 * arrays: horizontal before vertical.
3258 * Oh, size_error has the lowest
3259 * significance -- it will be checked
3260 * outside the arg loop.
3262 result = value_dup (v);
3263 value_release (val);
3264 goto done;
3265 case VALUE_FLOAT:
3266 data[i][y * thissizex + x] = value_get_as_float (v);
3267 break;
3268 case VALUE_BOOLEAN:
3269 data[i][y * thissizex + x] =
3270 ignore_bools
3271 ? 0.0
3272 : value_get_as_float (v);
3273 break;
3274 default :
3275 /* Ignore strings to be consistent with XL */
3276 data[i][y * thissizex + x] = 0.;
3280 value_release (val);
3283 if (size_error) {
3285 * If we found no errors in the data set and also the sizes
3286 * do not match, we will get here.
3288 result = value_new_error_VALUE (ei->pos);
3289 } else {
3291 void *state = gnm_accumulator_start ();
3292 GnmAccumulator *acc = gnm_accumulator_new ();
3293 int j;
3295 for (j = 0; j < sizex * sizey; j++) {
3296 int i;
3297 GnmQuad product;
3298 gnm_quad_init (&product, data[0][j]);
3299 for (i = 1; i < argc; i++) {
3300 GnmQuad q;
3301 gnm_quad_init (&q, data[i][j]);
3302 gnm_quad_mul (&product, &product, &q);
3304 gnm_accumulator_add_quad (acc, &product);
3307 result = value_new_float (gnm_accumulator_value (acc));
3308 gnm_accumulator_free (acc);
3309 gnm_accumulator_end (state);
3312 done:
3313 for (i = 0; i < argc; i++)
3314 g_free (data[i]);
3315 g_free (data);
3316 return result;
3319 static GnmValue *
3320 gnumeric_sumproduct (GnmFuncEvalInfo *ei, int argc, GnmExprConstPtr const *argv)
3322 return gnumeric_sumproduct_common (TRUE, ei, argc, argv);
3325 static GnmValue *
3326 gnumeric_odf_sumproduct (GnmFuncEvalInfo *ei, int argc, GnmExprConstPtr const *argv)
3328 return gnumeric_sumproduct_common (FALSE, ei, argc, argv);
3331 /***************************************************************************/
3333 static GnmFuncHelp const help_eigen[] = {
3334 { GNM_FUNC_HELP_NAME, F_("EIGEN:eigenvalues and eigenvectors of the symmetric @{matrix}")},
3335 { GNM_FUNC_HELP_ARG, F_("matrix:a symmetric matrix")},
3336 { GNM_FUNC_HELP_NOTE, F_("If @{matrix} is not symmetric, matching off-diagonal cells will be averaged on the assumption that the non-symmetry is caused by unimportant rounding errors.") },
3337 { GNM_FUNC_HELP_NOTE, F_("If @{matrix} does not contain an equal number of columns and rows, EIGEN returns #VALUE!") },
3338 // { GNM_FUNC_HELP_EXAMPLES, "=EIGEN({1,2;3,2})" },
3339 { GNM_FUNC_HELP_END}
3343 typedef struct {
3344 gnm_float val;
3345 int index;
3346 } gnumeric_eigen_ev_t;
3348 static int
3349 compare_gnumeric_eigen_ev (const void *a, const void *b)
3351 const gnumeric_eigen_ev_t *da = a;
3352 const gnumeric_eigen_ev_t *db = b;
3353 gnm_float ea = da->val;
3354 gnm_float eb = db->val;
3356 /* Compare first by magnitude (descending). */
3357 if (gnm_abs (ea) > gnm_abs (eb))
3358 return -1;
3359 else if (gnm_abs (ea) < gnm_abs (eb))
3360 return +1;
3362 /* Then by value, i.e., sign, still descending. */
3363 if (ea > eb)
3364 return -1;
3365 else if (ea < eb)
3366 return +1;
3367 else
3368 return 0;
3371 static GnmValue *
3372 gnumeric_eigen (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
3374 GnmMatrix *A = NULL;
3375 GnmMatrix *EIG = NULL;
3376 gnm_float *eigenvalues = NULL;
3377 GnmValue *res = NULL;
3378 int i, c, r;
3379 gnumeric_eigen_ev_t *ev_sort;
3381 A = gnm_matrix_from_value (argv[0], &res, ei->pos);
3382 if (!A) goto out;
3384 if (A->cols != A->rows || gnm_matrix_is_empty (A)) {
3385 res = value_new_error_VALUE (ei->pos);
3386 goto out;
3389 make_symmetric (A);
3390 EIG = gnm_matrix_new (A->rows, A->cols);
3391 eigenvalues = g_new0 (gnm_float, A->cols);
3393 if (!gnm_matrix_eigen (A, EIG, eigenvalues)) {
3394 res = value_new_error_NUM (ei->pos);
3395 goto out;
3398 /* Sorting eigenvalues */
3399 ev_sort = g_new (gnumeric_eigen_ev_t, A->cols);
3400 for (i = 0; i < A->cols; i++) {
3401 ev_sort[i].val = eigenvalues[i];
3402 ev_sort[i].index = i;
3404 qsort (ev_sort, A->cols, sizeof (gnumeric_eigen_ev_t), compare_gnumeric_eigen_ev);
3406 res = value_new_array_non_init (A->cols, A->rows + 1);
3407 for (c = 0; c < A->cols; ++c) {
3408 res->v_array.vals[c] = g_new (GnmValue *, A->rows + 1);
3409 res->v_array.vals[c][0] = value_new_float (eigenvalues[ev_sort[c].index]);
3410 for (r = 0; r < A->rows; ++r) {
3411 gnm_float tmp = EIG->data[r][ev_sort[c].index];
3412 res->v_array.vals[c][r + 1] = value_new_float (tmp);
3416 g_free (ev_sort);
3418 out:
3419 if (A) gnm_matrix_unref (A);
3420 if (EIG) gnm_matrix_unref (EIG);
3421 g_free (eigenvalues);
3422 return res;
3426 /***************************************************************************/
3428 GnmFuncDescriptor const math_functions[] = {
3429 { "abs", "f", help_abs,
3430 gnumeric_abs, NULL,
3431 GNM_FUNC_SIMPLE + GNM_FUNC_AUTO_FIRST,
3432 GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3433 { "acos", "f", help_acos,
3434 gnumeric_acos, NULL,
3435 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3436 { "acosh", "f", help_acosh,
3437 gnumeric_acosh, NULL,
3438 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3439 { "acot", "f", help_acot,
3440 gnumeric_acot, NULL,
3441 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_NO_TESTSUITE },
3442 { "acoth", "f", help_acoth,
3443 gnumeric_acoth, NULL,
3444 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_NO_TESTSUITE },
3445 { "agm", "ff", help_agm,
3446 gnumeric_agm, NULL,
3447 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3448 { "arabic", "S", help_arabic,
3449 gnumeric_arabic, NULL,
3450 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_NO_TESTSUITE },
3451 { "asin", "f", help_asin,
3452 gnumeric_asin, NULL,
3453 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3454 { "asinh", "f", help_asinh,
3455 gnumeric_asinh, NULL,
3456 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3457 { "atan", "f", help_atan,
3458 gnumeric_atan, NULL,
3459 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3460 { "atanh", "f", help_atanh,
3461 gnumeric_atanh, NULL,
3462 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3463 { "atan2", "ff", help_atan2,
3464 gnumeric_atan2, NULL,
3465 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3466 { "beta", "ff", help_beta,
3467 gnumeric_beta, NULL,
3468 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3469 { "betaln", "ff", help_betaln,
3470 gnumeric_betaln, NULL,
3471 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC, GNM_FUNC_TEST_STATUS_NO_TESTSUITE },
3472 { "cholesky","A", help_cholesky,
3473 gnumeric_cholesky, NULL,
3474 GNM_FUNC_RETURNS_NON_SCALAR, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC, GNM_FUNC_TEST_STATUS_NO_TESTSUITE },
3475 { "cos", "f", help_cos,
3476 gnumeric_cos, NULL,
3477 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3478 { "cosh", "f", help_cosh,
3479 gnumeric_cosh, NULL,
3480 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3481 { "cospi", "f", help_cospi,
3482 gnumeric_cospi, NULL,
3483 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3484 { "cot", "f", help_cot,
3485 gnumeric_cot, NULL,
3486 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_NO_TESTSUITE },
3487 { "cotpi", "f", help_cotpi,
3488 gnumeric_cotpi, NULL,
3489 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_NO_TESTSUITE },
3490 { "coth", "f", help_coth,
3491 gnumeric_coth, NULL,
3492 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_NO_TESTSUITE },
3494 { "countif", "rS", help_countif,
3495 gnumeric_countif, NULL,
3496 GNM_FUNC_SIMPLE + GNM_FUNC_AUTO_UNITLESS,
3497 GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3498 { "countifs", NULL, help_countifs,
3499 NULL, gnumeric_countifs,
3500 GNM_FUNC_SIMPLE + GNM_FUNC_AUTO_UNITLESS,
3501 GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3503 { "ceil", "f", help_ceil,
3504 gnumeric_ceil, NULL,
3505 GNM_FUNC_SIMPLE + GNM_FUNC_AUTO_FIRST,
3506 GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC, GNM_FUNC_TEST_STATUS_NO_TESTSUITE },
3507 { "ceiling", "f|f", help_ceiling,
3508 gnumeric_ceiling, NULL,
3509 GNM_FUNC_SIMPLE + GNM_FUNC_AUTO_FIRST,
3510 GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3511 { "degrees", "f", help_degrees,
3512 gnumeric_degrees, NULL,
3513 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3514 { "even", "f", help_even,
3515 gnumeric_even, NULL,
3516 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3517 { "exp", "f", help_exp,
3518 gnumeric_exp, NULL,
3519 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3520 { "expm1", "f", help_expm1,
3521 gnumeric_expm1, NULL,
3522 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3523 { "fact", "f", help_fact,
3524 gnumeric_fact, NULL,
3525 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_SUPERSET, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3527 /* MS Excel puts this in the engineering functions */
3528 { "factdouble", "f", help_factdouble,
3529 gnumeric_factdouble, NULL,
3530 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3532 { "fib", "f", help_fib,
3533 gnumeric_fib, NULL,
3534 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3535 { "combin", "ff", help_combin,
3536 gnumeric_combin, NULL,
3537 GNM_FUNC_SIMPLE + GNM_FUNC_AUTO_UNITLESS,
3538 GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3539 { "combina", "ff", help_combina,
3540 gnumeric_combina, NULL,
3541 GNM_FUNC_SIMPLE + GNM_FUNC_AUTO_UNITLESS,
3542 GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_NO_TESTSUITE },
3543 { "csc", "f", help_csc,
3544 gnumeric_csc, NULL,
3545 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC, GNM_FUNC_TEST_STATUS_NO_TESTSUITE },
3546 { "csch", "f", help_csch,
3547 gnumeric_csch, NULL,
3548 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC, GNM_FUNC_TEST_STATUS_NO_TESTSUITE },
3549 { "floor", "f|f", help_floor,
3550 gnumeric_floor, NULL,
3551 GNM_FUNC_SIMPLE + GNM_FUNC_AUTO_FIRST,
3552 GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3553 { "gamma", "f", help_gamma,
3554 gnumeric_gamma, NULL,
3555 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3556 { "gammaln", "f",
3557 help_gammaln, gnumeric_gammaln, NULL,
3558 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3559 { "gcd", NULL, help_gcd,
3560 NULL, gnumeric_gcd,
3561 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3562 { "gd", "f", help_gd,
3563 gnumeric_gd, NULL,
3564 GNM_FUNC_SIMPLE,
3565 GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3566 { "hypot", NULL, help_hypot,
3567 NULL, gnumeric_hypot,
3568 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC, GNM_FUNC_TEST_STATUS_NO_TESTSUITE },
3569 { "igamma", "ff|bbb", help_igamma,
3570 gnumeric_igamma, NULL,
3571 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC, GNM_FUNC_TEST_STATUS_NO_TESTSUITE },
3572 { "int", "f", help_int,
3573 gnumeric_int, NULL,
3574 GNM_FUNC_SIMPLE + GNM_FUNC_AUTO_FIRST,
3575 GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3576 { "lcm", NULL, help_lcm,
3577 NULL, gnumeric_lcm,
3578 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3579 { "ln", "f", help_ln,
3580 gnumeric_ln, NULL,
3581 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3582 { "ln1p", "f", help_ln1p,
3583 gnumeric_ln1p, NULL,
3584 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3585 { "log", "f|f", help_log,
3586 gnumeric_log, NULL,
3587 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3588 { "log2", "f", help_log2,
3589 gnumeric_log2, NULL,
3590 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3591 { "log10", "f", help_log10,
3592 gnumeric_log10, NULL,
3593 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3594 { "mod", "ff", help_mod,
3595 gnumeric_mod, NULL,
3596 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3597 { "mround", "ff", help_mround,
3598 gnumeric_mround, NULL,
3599 GNM_FUNC_SIMPLE + GNM_FUNC_AUTO_FIRST,
3600 GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3601 { "multinomial", NULL, help_multinomial,
3602 NULL, gnumeric_multinomial,
3603 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3604 { "odd" , "f", help_odd,
3605 gnumeric_odd, NULL,
3606 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3607 { "power", "ff|f", help_power,
3608 gnumeric_power, NULL,
3609 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_SUPERSET, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3610 { "pochhammer", "ff", help_pochhammer,
3611 gnumeric_pochhammer, NULL,
3612 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3613 { "g_product", NULL, help_g_product,
3614 NULL, gnumeric_g_product,
3615 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3616 { "quotient" , "ff", help_quotient,
3617 gnumeric_quotient, NULL,
3618 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3619 { "radians", "f", help_radians,
3620 gnumeric_radians, NULL,
3621 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3622 { "reducepi", "ff|f", help_reducepi,
3623 gnumeric_reducepi, NULL,
3624 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC, GNM_FUNC_TEST_STATUS_NO_TESTSUITE },
3625 { "roman", "f|f", help_roman,
3626 gnumeric_roman, NULL,
3627 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3628 { "round", "f|f", help_round,
3629 gnumeric_round, NULL,
3630 GNM_FUNC_SIMPLE + GNM_FUNC_AUTO_FIRST,
3631 GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3632 { "rounddown", "f|f", help_rounddown,
3633 gnumeric_rounddown, NULL,
3634 GNM_FUNC_SIMPLE + GNM_FUNC_AUTO_FIRST,
3635 GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3636 { "roundup", "f|f", help_roundup,
3637 gnumeric_roundup, NULL,
3638 GNM_FUNC_SIMPLE + GNM_FUNC_AUTO_FIRST,
3639 GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3640 { "sec", "f", help_sec,
3641 gnumeric_sec, NULL,
3642 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC, GNM_FUNC_TEST_STATUS_NO_TESTSUITE },
3643 { "sech", "f", help_sech,
3644 gnumeric_sech, NULL,
3645 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC, GNM_FUNC_TEST_STATUS_NO_TESTSUITE },
3646 { "seriessum", "fffA", help_seriessum,
3647 gnumeric_seriessum, NULL,
3648 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3649 { "sign", "f", help_sign,
3650 gnumeric_sign, NULL,
3651 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3652 { "sin", "f", help_sin,
3653 gnumeric_sin, NULL,
3654 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3655 { "sinh", "f", help_sinh,
3656 gnumeric_sinh, NULL,
3657 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3658 { "sinpi", "f", help_sinpi,
3659 gnumeric_sinpi, NULL,
3660 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3661 { "sqrt", "f", help_sqrt,
3662 gnumeric_sqrt, NULL,
3663 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3664 { "sqrtpi", "f", help_sqrtpi,
3665 gnumeric_sqrtpi, NULL,
3666 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3667 { "suma", NULL, help_suma,
3668 NULL, gnumeric_suma,
3669 GNM_FUNC_SIMPLE + GNM_FUNC_AUTO_FIRST,
3670 GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3671 { "sumif", "rS|r", help_sumif,
3672 gnumeric_sumif, NULL,
3673 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3674 { "sumifs", NULL, help_sumifs,
3675 NULL, gnumeric_sumifs,
3676 GNM_FUNC_SIMPLE,
3677 GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3678 { "averageif", "rS|r", help_averageif,
3679 gnumeric_averageif, NULL,
3680 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3681 { "averageifs", NULL, help_averageifs,
3682 NULL, gnumeric_averageifs,
3683 GNM_FUNC_SIMPLE,
3684 GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3685 { "minifs", NULL, help_minifs,
3686 NULL, gnumeric_minifs,
3687 GNM_FUNC_SIMPLE,
3688 GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3689 { "maxifs", NULL, help_maxifs,
3690 NULL, gnumeric_maxifs,
3691 GNM_FUNC_SIMPLE,
3692 GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3693 { "sumproduct", NULL, help_sumproduct,
3694 NULL, gnumeric_sumproduct,
3695 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3696 { "odf.sumproduct", NULL, help_odf_sumproduct,
3697 NULL, gnumeric_odf_sumproduct,
3698 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_NO_TESTSUITE },
3699 { "sumsq", NULL, help_sumsq,
3700 NULL, gnumeric_sumsq,
3701 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3702 { "sumx2my2", "AA", help_sumx2my2,
3703 gnumeric_sumx2my2, NULL,
3704 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3705 { "sumx2py2", "AA", help_sumx2py2,
3706 gnumeric_sumx2py2, NULL,
3707 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3708 { "sumxmy2", "AA", help_sumxmy2,
3709 gnumeric_sumxmy2, NULL,
3710 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3711 { "tan", "f", help_tan,
3712 gnumeric_tan, NULL,
3713 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3714 { "tanpi", "f", help_tanpi,
3715 gnumeric_tanpi, NULL,
3716 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3717 { "tanh", "f", help_tanh,
3718 gnumeric_tanh, NULL,
3719 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3720 { "trunc", "f|f", help_trunc,
3721 gnumeric_trunc, NULL,
3722 GNM_FUNC_SIMPLE + GNM_FUNC_AUTO_FIRST,
3723 GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3724 { "pi", "", help_pi,
3725 gnumeric_pi, NULL,
3726 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3727 { "mmult", "AA", help_mmult,
3728 gnumeric_mmult, NULL,
3729 GNM_FUNC_RETURNS_NON_SCALAR, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3730 { "minverse","A", help_minverse,
3731 gnumeric_minverse, NULL,
3732 GNM_FUNC_RETURNS_NON_SCALAR, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3733 { "mpseudoinverse","A|f", help_mpseudoinverse,
3734 gnumeric_mpseudoinverse, NULL,
3735 GNM_FUNC_RETURNS_NON_SCALAR, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC, GNM_FUNC_TEST_STATUS_NO_TESTSUITE },
3736 { "linsolve", "AA", help_linsolve,
3737 gnumeric_linsolve, NULL,
3738 GNM_FUNC_RETURNS_NON_SCALAR, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC, GNM_FUNC_TEST_STATUS_NO_TESTSUITE },
3739 { "mdeterm", "A", help_mdeterm,
3740 gnumeric_mdeterm, NULL,
3741 GNM_FUNC_RETURNS_NON_SCALAR, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3742 { "munit","f", help_munit,
3743 gnumeric_munit, NULL,
3744 GNM_FUNC_RETURNS_NON_SCALAR, GNM_FUNC_IMPL_STATUS_COMPLETE,
3745 GNM_FUNC_TEST_STATUS_NO_TESTSUITE },
3746 { "eigen","A", help_eigen,
3747 gnumeric_eigen, NULL,
3748 GNM_FUNC_RETURNS_NON_SCALAR, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC, GNM_FUNC_TEST_STATUS_NO_TESTSUITE},
3749 #if 0
3750 { "logmdeterm", "A|si",
3751 help_logmdeterm, gnumeric_logmdeterm, NULL, NULL, NULL },
3752 #endif
3753 {NULL}
3756 G_MODULE_EXPORT void
3757 go_plugin_init (GOPlugin *plugin, GOCmdContext *cc)
3759 g_signal_connect (gnm_func_lookup ("sumsq", NULL),
3760 "derivative", G_CALLBACK (gnumeric_sumsq_deriv), NULL);
3761 g_signal_connect (gnm_func_lookup ("exp", NULL),
3762 "derivative", G_CALLBACK (gnumeric_exp_deriv), NULL);
3763 g_signal_connect (gnm_func_lookup ("ln", NULL),
3764 "derivative", G_CALLBACK (gnumeric_ln_deriv), NULL);
3767 G_MODULE_EXPORT void
3768 go_plugin_shutdown (GOPlugin *plugin, GOCmdContext *cc)