1 /*
2 * fn-math.c: Built in mathematical functions and functions registration
3 *
4 * Authors:
5 * Miguel de Icaza (miguel@gnu.org)
6 * Jukka-Pekka Iivonen (iivonen@iki.fi)
7 * Morten Welinder (terra@gnome.org)
8 *
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.
13 *
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.
18 *
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/>.
21 */
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>
40
41 #include <goffice/goffice.h>
42 #include <gnm-plugin.h>
43
44 #include <math.h>
45 #include <string.h>
46
47 #define UNICODE_PI "\360\235\234\213"
48 #define UNICODE_MINUS "\xe2\x88\x92"
49
50 GNM_PLUGIN_MODULE_HEADER;
51
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).")
56
57 /***************************************************************************/
58
59 static GnmValue *
oldstyle_if_func(GnmFuncEvalInfo * ei,GnmValue const * const * argv,float_range_function_t fun,GnmStdError err,CollectFlags flags)60 oldstyle_if_func (GnmFuncEvalInfo *ei, GnmValue const * const *argv,
61 float_range_function_t fun, GnmStdError err,
62 CollectFlags flags)
63 {
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;
71
72 g_ptr_array_add (data, (gpointer)(argv[0]));
73 g_ptr_array_add (crits, parse_criteria (argv[1], date_conv, TRUE));
74
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.
85
86 // For now, bail.
87 res = value_new_error_VALUE (ei->pos);
88 goto out;
89 }
90 } else {
91 vals = argv[0];
92 insanity = FALSE;
93 }
94
95 res = gnm_ifs_func (data, crits, vals,
96 fun, err, ei->pos,
97 flags);
98
99 out:
100 g_ptr_array_free (data, TRUE);
101 g_ptr_array_free (crits, TRUE);
102
103 return res;
104 }
105
106 static GnmValue *
newstyle_if_func(GnmFuncEvalInfo * ei,int argc,GnmExprConstPtr const * argv,float_range_function_t fun,GnmStdError err,gboolean no_data)107 newstyle_if_func (GnmFuncEvalInfo *ei, int argc, GnmExprConstPtr const *argv,
108 float_range_function_t fun, GnmStdError err,
109 gboolean no_data)
110 {
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;
119
120 if ((argc - cstart) & 1) {
121 res = value_new_error_VALUE (ei->pos);
122 goto out;
123 }
124
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;
132 }
133 if (!VALUE_IS_CELLRANGE (vals)) {
134 res = value_new_error_VALUE (ei->pos);
135 goto out;
136 }
137 }
138
139 for (i = cstart; i + 1 < argc; i += 2) {
140 GnmValue *area, *crit;
141
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;
148 }
149 if (no_data && !vals)
150 vals = value_dup (area);
151 g_ptr_array_add (data, area);
152
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;
158 }
159
160 g_ptr_array_add (crits, parse_criteria (crit, date_conv, TRUE));
161 value_release (crit);
162 }
163
164 if (!vals) {
165 // COUNTIFS with no arguments.
166 res = value_new_error_VALUE (ei->pos);
167 goto out;
168 }
169
170 res = gnm_ifs_func (data, crits, vals,
171 fun, err, ei->pos,
172 (no_data
173 ? 0
174 : COLLECT_IGNORE_STRINGS |
175 COLLECT_IGNORE_BLANKS |
176 COLLECT_IGNORE_BOOLS));
177
178 out:
179 g_ptr_array_free (data, TRUE);
180 g_ptr_array_free (crits, TRUE);
181 value_release (vals);
182
183 return res;
184 }
185
186 /***************************************************************************/
187
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}
199 };
200
201 static const gnm_float gnm_gcd_max = 1 / GNM_EPSILON;
202
203 static gnm_float
gnm_gcd(gnm_float a,gnm_float b)204 gnm_gcd (gnm_float a, gnm_float b)
205 {
206 while (b > 0.5) {
207 gnm_float r = gnm_fmod (a, b);
208 a = b;
209 b = r;
210 }
211 return a;
212 }
213
214 static int
range_gcd(gnm_float const * xs,int n,gnm_float * res)215 range_gcd (gnm_float const *xs, int n, gnm_float *res)
216 {
217 if (n > 0) {
218 int i;
219 gnm_float gcd_so_far = gnm_fake_floor (xs[0]);
220
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);
227 }
228
229 if (gcd_so_far == 0)
230 return 1;
231
232 *res = gcd_so_far;
233 return 0;
234 } else
235 return 1;
236 }
237
238 static GnmValue *
gnumeric_gcd(GnmFuncEvalInfo * ei,int argc,GnmExprConstPtr const * argv)239 gnumeric_gcd (GnmFuncEvalInfo *ei, int argc, GnmExprConstPtr const *argv)
240 {
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);
247 }
248
249 /***************************************************************************/
250
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}
262 };
263
264 static gnm_float
gnm_lcm(gnm_float a,gnm_float b)265 gnm_lcm (gnm_float a, gnm_float b)
266 {
267 return a * (b / gnm_gcd (a, b));
268 }
269
270 static int
range_lcm(gnm_float const * xs,int n,gnm_float * res)271 range_lcm (gnm_float const *xs, int n, gnm_float *res)
272 {
273 int i;
274 gnm_float lcm;
275
276 if (n <= 0)
277 return 1;
278
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);
287 }
288
289 *res = lcm;
290 return 0;
291 }
292
293 static GnmValue *
gnumeric_lcm(GnmFuncEvalInfo * ei,int argc,GnmExprConstPtr const * argv)294 gnumeric_lcm (GnmFuncEvalInfo *ei, int argc, GnmExprConstPtr const *argv)
295 {
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);
302
303 }
304
305 /***************************************************************************/
306
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 }
315 };
316
317 static gnm_float
gnm_gd(gnm_float x)318 gnm_gd (gnm_float x)
319 {
320 return 2 * gnm_atan (gnm_tanh (x / 2));
321 }
322
323 static GnmValue *
gnumeric_gd(GnmFuncEvalInfo * ei,GnmValue const * const * argv)324 gnumeric_gd (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
325 {
326 return value_new_float (gnm_gd (value_get_as_float (argv[0])));
327 }
328
329 /***************************************************************************/
330
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}
338 };
339
340 static GnmValue *
gnumeric_hypot(GnmFuncEvalInfo * ei,int argc,GnmExprConstPtr const * argv)341 gnumeric_hypot (GnmFuncEvalInfo *ei, int argc, GnmExprConstPtr const *argv)
342 {
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);
349
350 }
351
352 /***************************************************************************/
353
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}
363 };
364
365 static GnmValue *
gnumeric_abs(GnmFuncEvalInfo * ei,GnmValue const * const * argv)366 gnumeric_abs (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
367 {
368 return value_new_float (gnm_abs (value_get_as_float (argv[0])));
369 }
370
371 /***************************************************************************/
372
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}
381 };
382
383 static GnmValue *
gnumeric_acos(GnmFuncEvalInfo * ei,GnmValue const * const * argv)384 gnumeric_acos (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
385 {
386 gnm_float t = value_get_as_float (argv[0]);
387
388 if (t < -1.0 || t > 1.0)
389 return value_new_error_NUM (ei->pos);
390 return value_new_float (gnm_acos (t));
391 }
392
393 /***************************************************************************/
394
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}
403 };
404
405 static GnmValue *
gnumeric_acosh(GnmFuncEvalInfo * ei,GnmValue const * const * argv)406 gnumeric_acosh (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
407 {
408 gnm_float t = value_get_as_float (argv[0]);
409
410 if (t < 1.0)
411 return value_new_error_NUM (ei->pos);
412
413 return value_new_float (gnm_acosh (t));
414 }
415
416 /***************************************************************************/
417
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 }
426 };
427
428 static GnmValue *
gnumeric_acot(GnmFuncEvalInfo * ei,GnmValue const * const * argv)429 gnumeric_acot (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
430 {
431 return value_new_float (gnm_acot (value_get_as_float (argv[0])));
432 }
433
434 /***************************************************************************/
435
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 }
444 };
445
446 static GnmValue *
gnumeric_acoth(GnmFuncEvalInfo * ei,GnmValue const * const * argv)447 gnumeric_acoth (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
448 {
449 return value_new_float (gnm_acoth (value_get_as_float (argv[0])));
450 }
451
452 /***************************************************************************/
453
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}
465 };
466
467 static GnmValue *
gnumeric_asin(GnmFuncEvalInfo * ei,GnmValue const * const * argv)468 gnumeric_asin (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
469 {
470 gnm_float t = value_get_as_float (argv[0]);
471
472 if (t < -1.0 || t > 1.0)
473 return value_new_error_NUM (ei->pos);
474
475 return value_new_float (gnm_asin (t));
476 }
477
478 /***************************************************************************/
479
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}
489 };
490
491 static GnmValue *
gnumeric_asinh(GnmFuncEvalInfo * ei,GnmValue const * const * argv)492 gnumeric_asinh (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
493 {
494 return value_new_float (gnm_asinh (value_get_as_float (argv[0])));
495 }
496
497 /***************************************************************************/
498
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}
513 };
514
515 static GnmValue *
gnumeric_atan(GnmFuncEvalInfo * ei,GnmValue const * const * argv)516 gnumeric_atan (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
517 {
518 return value_new_float (gnm_atan (value_get_as_float (argv[0])));
519 }
520
521 /***************************************************************************/
522
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}
533 };
534
535 static GnmValue *
gnumeric_atanh(GnmFuncEvalInfo * ei,GnmValue const * const * argv)536 gnumeric_atanh (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
537 {
538 gnm_float t = value_get_as_float (argv[0]);
539
540 if (t <= -1.0 || t >= 1.0)
541 return value_new_error_NUM (ei->pos);
542
543 return value_new_float (gnm_atanh (value_get_as_float (argv[0])));
544 }
545
546 /***************************************************************************/
547
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}
568 };
569
570 static GnmValue *
gnumeric_atan2(GnmFuncEvalInfo * ei,GnmValue const * const * argv)571 gnumeric_atan2 (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
572 {
573 gnm_float x = value_get_as_float (argv[0]);
574 gnm_float y = value_get_as_float (argv[1]);
575
576 if (x == 0 && y == 0)
577 return value_new_error_DIV0 (ei->pos);
578
579 return value_new_float (gnm_atan2 (y, x));
580 }
581 /***************************************************************************/
582
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}
592 };
593
594 static GnmValue *
gnumeric_agm(GnmFuncEvalInfo * ei,GnmValue const * const * argv)595 gnumeric_agm (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
596 {
597 gnm_float a = value_get_as_float (argv[0]);
598 gnm_float b = value_get_as_float (argv[1]);
599
600 return value_new_float (gnm_agm (a, b));
601 }
602
603 /***************************************************************************/
604
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 }
615 };
616
617 static GnmValue *
gnumeric_ceil(GnmFuncEvalInfo * ei,GnmValue const * const * argv)618 gnumeric_ceil (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
619 {
620 return value_new_float (gnm_fake_ceil (value_get_as_float (argv[0])));
621 }
622
623 /***************************************************************************/
624
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}
632 };
633
634 static GnmValue *
gnumeric_countif(GnmFuncEvalInfo * ei,GnmValue const * const * argv)635 gnumeric_countif (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
636 {
637 GnmValue const * argv3[3];
638
639 argv3[0] = argv[0];
640 argv3[1] = argv[1];
641 argv3[2] = NULL;
642
643 return oldstyle_if_func (ei, argv3, gnm_range_count, GNM_ERROR_DIV0,
644 0);
645 }
646
647 /***************************************************************************/
648
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}
656 };
657
658 static GnmValue *
gnumeric_countifs(GnmFuncEvalInfo * ei,int argc,GnmExprConstPtr const * argv)659 gnumeric_countifs (GnmFuncEvalInfo *ei, int argc, GnmExprConstPtr const *argv)
660 {
661 return newstyle_if_func (ei, argc, argv,
662 gnm_range_count, GNM_ERROR_DIV0,
663 TRUE);
664 }
665
666 /***************************************************************************/
667
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}
681 };
682
683 static GnmValue *
gnumeric_sumif(GnmFuncEvalInfo * ei,GnmValue const * const * argv)684 gnumeric_sumif (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
685 {
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);
690 }
691
692 /***************************************************************************/
693
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}
702 };
703
704 static GnmValue *
gnumeric_sumifs(GnmFuncEvalInfo * ei,int argc,GnmExprConstPtr const * argv)705 gnumeric_sumifs (GnmFuncEvalInfo *ei, int argc, GnmExprConstPtr const *argv)
706 {
707 return newstyle_if_func (ei, argc, argv,
708 gnm_range_sum, GNM_ERROR_DIV0,
709 FALSE);
710 }
711
712 /***************************************************************************/
713
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}
722 };
723
724 static GnmValue *
gnumeric_averageif(GnmFuncEvalInfo * ei,GnmValue const * const * argv)725 gnumeric_averageif (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
726 {
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);
731 }
732
733 /***************************************************************************/
734
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}
743 };
744
745 static GnmValue *
gnumeric_averageifs(GnmFuncEvalInfo * ei,int argc,GnmExprConstPtr const * argv)746 gnumeric_averageifs (GnmFuncEvalInfo *ei, int argc, GnmExprConstPtr const *argv)
747 {
748 return newstyle_if_func (ei, argc, argv,
749 gnm_range_average, GNM_ERROR_DIV0,
750 FALSE);
751 }
752
753 /***************************************************************************/
754
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}
763 };
764
765 static GnmValue *
gnumeric_minifs(GnmFuncEvalInfo * ei,int argc,GnmExprConstPtr const * argv)766 gnumeric_minifs (GnmFuncEvalInfo *ei, int argc, GnmExprConstPtr const *argv)
767 {
768 return newstyle_if_func (ei, argc, argv,
769 gnm_range_min, GNM_ERROR_DIV0,
770 FALSE);
771 }
772
773 /***************************************************************************/
774
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}
783 };
784
785 static GnmValue *
gnumeric_maxifs(GnmFuncEvalInfo * ei,int argc,GnmExprConstPtr const * argv)786 gnumeric_maxifs (GnmFuncEvalInfo *ei, int argc, GnmExprConstPtr const *argv)
787 {
788 return newstyle_if_func (ei, argc, argv,
789 gnm_range_max, GNM_ERROR_DIV0,
790 FALSE);
791 }
792
793 /***************************************************************************/
794
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 }
809 };
810
811 static GnmValue *
gnumeric_ceiling(GnmFuncEvalInfo * ei,GnmValue const * const * argv)812 gnumeric_ceiling (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
813 {
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);
816
817 if (x == 0 || s == 0)
818 return value_new_int (0);
819
820 if (x / s < 0)
821 return value_new_error_NUM (ei->pos);
822
823 return value_new_float (gnm_fake_ceil (x / s) * s);
824 }
825
826 /***************************************************************************/
827
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 }
838 };
839
840 static GnmValue *
gnumeric_cos(GnmFuncEvalInfo * ei,GnmValue const * const * argv)841 gnumeric_cos (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
842 {
843 return value_new_float (gnm_cos (value_get_as_float (argv[0])));
844 }
845
846 /***************************************************************************/
847
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 }
855 };
856
857 static GnmValue *
gnumeric_cospi(GnmFuncEvalInfo * ei,GnmValue const * const * argv)858 gnumeric_cospi (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
859 {
860 return value_new_float (gnm_cospi (value_get_as_float (argv[0])));
861 }
862
863 /***************************************************************************/
864
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 }
873 };
874
875 static GnmValue *
gnumeric_cosh(GnmFuncEvalInfo * ei,GnmValue const * const * argv)876 gnumeric_cosh (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
877 {
878 return value_new_float (gnm_cosh (value_get_as_float (argv[0])));
879 }
880
881 /***************************************************************************/
882
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 }
891 };
892
893 static GnmValue *
gnumeric_cot(GnmFuncEvalInfo * ei,GnmValue const * const * argv)894 gnumeric_cot (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
895 {
896 return value_new_float (gnm_cot (value_get_as_float (argv[0])));
897 }
898
899 /***************************************************************************/
900
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 }
908 };
909
910 static GnmValue *
gnumeric_cotpi(GnmFuncEvalInfo * ei,GnmValue const * const * argv)911 gnumeric_cotpi (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
912 {
913 return value_new_float (gnm_cotpi (value_get_as_float (argv[0])));
914 }
915
916 /***************************************************************************/
917
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 }
926 };
927
928 static GnmValue *
gnumeric_coth(GnmFuncEvalInfo * ei,GnmValue const * const * argv)929 gnumeric_coth (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
930 {
931 return value_new_float (gnm_coth (value_get_as_float (argv[0])));
932 }
933
934 /***************************************************************************/
935
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}
943 };
944
945 static GnmValue *
gnumeric_degrees(GnmFuncEvalInfo * ei,GnmValue const * const * argv)946 gnumeric_degrees (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
947 {
948 return value_new_float ((value_get_as_float (argv[0]) * 180.0) /
949 M_PIgnum);
950 }
951
952 /***************************************************************************/
953
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}
962 };
963
964 static GnmValue *
gnumeric_exp(GnmFuncEvalInfo * ei,GnmValue const * const * argv)965 gnumeric_exp (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
966 {
967 return value_new_float (gnm_exp (value_get_as_float (argv[0])));
968 }
969
970 static GnmExpr const *
gnumeric_exp_deriv(GnmFunc * func,GnmExpr const * expr,GnmEvalPos const * ep,GnmExprDeriv * info)971 gnumeric_exp_deriv (GnmFunc *func, GnmExpr const *expr, GnmEvalPos const *ep,
972 GnmExprDeriv *info)
973 {
974 return gnm_expr_deriv_chain (expr, gnm_expr_copy (expr), ep, info);
975 }
976
977 /***************************************************************************/
978
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}
986 };
987
988 static GnmValue *
gnumeric_expm1(GnmFuncEvalInfo * ei,GnmValue const * const * argv)989 gnumeric_expm1 (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
990 {
991 return value_new_float (gnm_expm1 (value_get_as_float (argv[0])));
992 }
993
994 /***************************************************************************/
995
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}
1004 };
1005
1006 static GnmValue *
gnumeric_fact(GnmFuncEvalInfo * ei,GnmValue const * const * argv)1007 gnumeric_fact (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1008 {
1009 gnm_float x = value_get_as_float (argv[0]);
1010 gboolean x_is_integer = (x == gnm_floor (x));
1011
1012 if (x < 0 && x_is_integer)
1013 return value_new_error_NUM (ei->pos);
1014
1015 return value_new_float (gnm_fact (x));
1016 }
1017
1018 /***************************************************************************/
1019
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}
1027 };
1028
1029 static GnmValue *
gnumeric_gamma(GnmFuncEvalInfo * ei,GnmValue const * const * argv)1030 gnumeric_gamma (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1031 {
1032 return value_new_float (gnm_gamma (value_get_as_float (argv[0])));
1033 }
1034
1035 /***************************************************************************/
1036
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 }
1044 };
1045
1046 static GnmValue *
gnumeric_gammaln(GnmFuncEvalInfo * ei,GnmValue const * const * argv)1047 gnumeric_gammaln (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1048 {
1049 gnm_float x = value_get_as_float (argv[0]);
1050 gboolean x_is_integer = (x == gnm_floor (x));
1051
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));
1057 }
1058
1059 /***************************************************************************/
1060
1061 static GnmFuncHelp const help_digamma[] = {
1062 { GNM_FUNC_HELP_NAME, F_("DIGAMMA:the Digamma function")},
1063 { GNM_FUNC_HELP_ARG, F_("x:number")},
1064 { GNM_FUNC_HELP_EXAMPLES, "=DIGAMMA(1.46)" },
1065 { GNM_FUNC_HELP_EXAMPLES, "=DIGAMMA(15000)" },
1066 { GNM_FUNC_HELP_SEEALSO, "GAMMA"},
1067 { GNM_FUNC_HELP_END}
1068 };
1069
1070 static GnmValue *
gnumeric_digamma(GnmFuncEvalInfo * ei,GnmValue const * const * argv)1071 gnumeric_digamma (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1072 {
1073 return value_new_float (gnm_digamma (value_get_as_float (argv[0])));
1074 }
1075
1076 /***************************************************************************/
1077 static GnmFuncHelp const help_igamma[] = {
1078 { GNM_FUNC_HELP_NAME, F_("IGAMMA:the incomplete Gamma function")},
1079 { GNM_FUNC_HELP_ARG, F_("a:number")},
1080 { GNM_FUNC_HELP_ARG, F_("x:number")},
1081 { GNM_FUNC_HELP_ARG, F_("lower:if true (the default), the lower incomplete gamma function, otherwise the upper incomplete gamma function")},
1082 { GNM_FUNC_HELP_ARG, F_("regularize:if true (the default), the regularized version of the incomplete gamma function")},
1083 { GNM_FUNC_HELP_ARG, F_("real:if true (the default), the real part of the result, otherwise the imaginary part")},
1084 { GNM_FUNC_HELP_NOTE, F_("The regularized incomplete gamma function is the unregularized incomplete gamma function divided by GAMMA(@{a})") },
1085 { GNM_FUNC_HELP_NOTE, F_("This is a real valued function as long as neither @{a} nor @{z} are negative.") },
1086 { GNM_FUNC_HELP_EXAMPLES, "=IGAMMA(2.5,-1.8,TRUE,TRUE,TRUE)" },
1087 { GNM_FUNC_HELP_EXAMPLES, "=IGAMMA(2.5,-1.8,TRUE,TRUE,FALSE)" },
1088 { GNM_FUNC_HELP_SEEALSO, "GAMMA,IMIGAMMA"},
1089 { GNM_FUNC_HELP_END}
1090 };
1091
1092 static GnmValue *
gnumeric_igamma(GnmFuncEvalInfo * ei,GnmValue const * const * argv)1093 gnumeric_igamma (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1094 {
1095 gnm_float a = value_get_as_float (argv[0]);
1096 gnm_float z = value_get_as_float (argv[1]);
1097 gboolean lower = argv[2] ? value_get_as_checked_bool (argv[2]) : TRUE;
1098 gboolean reg = argv[3] ? value_get_as_checked_bool (argv[3]) : TRUE;
1099 gboolean re = argv[4] ? value_get_as_checked_bool (argv[4]) : TRUE;
1100 gnm_complex ig;
1101
1102 ig = gnm_complex_igamma (GNM_CREAL (a), GNM_CREAL (z), lower, reg);
1103
1104 return value_new_float (re ? ig.re : ig.im);
1105 }
1106
1107 /***************************************************************************/
1108
1109 static GnmFuncHelp const help_beta[] = {
1110 { GNM_FUNC_HELP_NAME, F_("BETA:Euler beta function")},
1111 { GNM_FUNC_HELP_ARG, F_("x:number")},
1112 { GNM_FUNC_HELP_ARG, F_("y:number")},
1113 { 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.")},
1114 { GNM_FUNC_HELP_NOTE, F_("If @{x}, @{y}, or (@{x} + @{y}) are non-positive integers, BETA returns #NUM!") },
1115 { GNM_FUNC_HELP_EXAMPLES, "=BETA(2,3)" },
1116 { GNM_FUNC_HELP_EXAMPLES, "=BETA(-0.5,0.5)" },
1117 { GNM_FUNC_HELP_SEEALSO, "BETALN,GAMMALN"},
1118 { GNM_FUNC_HELP_EXTREF, F_("wiki:en:Beta_function") },
1119 { GNM_FUNC_HELP_END}
1120 };
1121
1122 static GnmValue *
gnumeric_beta(GnmFuncEvalInfo * ei,GnmValue const * const * argv)1123 gnumeric_beta (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1124 {
1125 gnm_float a = value_get_as_float (argv[0]);
1126 gnm_float b = value_get_as_float (argv[1]);
1127
1128 return value_new_float (gnm_beta (a, b));
1129 }
1130
1131 /***************************************************************************/
1132
1133 static GnmFuncHelp const help_betaln[] = {
1134 { GNM_FUNC_HELP_NAME, F_("BETALN:natural logarithm of the absolute value of the Euler beta function")},
1135 { GNM_FUNC_HELP_ARG, F_("x:number")},
1136 { GNM_FUNC_HELP_ARG, F_("y:number")},
1137 { 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.")},
1138 { GNM_FUNC_HELP_NOTE, F_("If @{x}, @{y}, or (@{x} + @{y}) are non-positive integers, BETALN returns #NUM!") },
1139 { GNM_FUNC_HELP_EXAMPLES, "=BETALN(2,3)" },
1140 { GNM_FUNC_HELP_EXAMPLES, "=BETALN(-0.5,0.5)" },
1141 { GNM_FUNC_HELP_SEEALSO, "BETA,GAMMALN"},
1142 { GNM_FUNC_HELP_EXTREF, F_("wiki:en:Beta_function") },
1143 { GNM_FUNC_HELP_END}
1144 };
1145
1146 static GnmValue *
gnumeric_betaln(GnmFuncEvalInfo * ei,GnmValue const * const * argv)1147 gnumeric_betaln (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1148 {
1149 gnm_float a = value_get_as_float (argv[0]);
1150 gnm_float b = value_get_as_float (argv[1]);
1151 int sign;
1152
1153 return value_new_float (gnm_lbeta3 (a, b, &sign));
1154 }
1155
1156 /***************************************************************************/
1157
1158 static GnmFuncHelp const help_combin[] = {
1159 { GNM_FUNC_HELP_NAME, F_("COMBIN:binomial coefficient")},
1160 { GNM_FUNC_HELP_ARG, F_("n:non-negative integer")},
1161 { GNM_FUNC_HELP_ARG, F_("k:non-negative integer")},
1162 { GNM_FUNC_HELP_DESCRIPTION, F_("COMBIN returns the binomial coefficient \"@{n} choose @{k}\","
1163 " the number of @{k}-combinations of an @{n}-element set "
1164 "without repetition.")},
1165 { GNM_FUNC_HELP_NOTE, F_("If @{n} is less than @{k} COMBIN returns #NUM!") },
1166 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
1167 { GNM_FUNC_HELP_ODF, F_("This function is OpenFormula compatible.") },
1168 { GNM_FUNC_HELP_EXAMPLES, "=COMBIN(8,6)" },
1169 { GNM_FUNC_HELP_EXAMPLES, "=COMBIN(6,2)" },
1170 { GNM_FUNC_HELP_EXTREF, F_("wiki:en:Binomial_coefficient") },
1171 { GNM_FUNC_HELP_END}
1172 };
1173
1174
1175 static GnmValue *
gnumeric_combin(GnmFuncEvalInfo * ei,GnmValue const * const * argv)1176 gnumeric_combin (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1177 {
1178 gnm_float n = gnm_floor (value_get_as_float (argv[0]));
1179 gnm_float k = gnm_floor (value_get_as_float (argv[1]));
1180
1181 if (k >= 0 && n >= k)
1182 return value_new_float (combin (n ,k));
1183
1184 return value_new_error_NUM (ei->pos);
1185 }
1186
1187 /***************************************************************************/
1188
1189 static GnmFuncHelp const help_combina[] = {
1190 { GNM_FUNC_HELP_NAME, F_("COMBINA:the number of @{k}-combinations of an @{n}-element set "
1191 "with repetition")},
1192 { GNM_FUNC_HELP_ARG, F_("n:non-negative integer")},
1193 { GNM_FUNC_HELP_ARG, F_("k:non-negative integer")},
1194 { GNM_FUNC_HELP_ODF, F_("This function is OpenFormula compatible.") },
1195 { GNM_FUNC_HELP_EXAMPLES, "=COMBINA(5,3)" },
1196 { GNM_FUNC_HELP_EXAMPLES, "=COMBINA(6,3)" },
1197 { GNM_FUNC_HELP_EXAMPLES, "=COMBINA(42,3)" },
1198 { GNM_FUNC_HELP_EXTREF, F_("wiki:en:Multiset") },
1199 { GNM_FUNC_HELP_SEEALSO, "COMBIN" },
1200 { GNM_FUNC_HELP_END}
1201 };
1202
1203
1204 static GnmValue *
gnumeric_combina(GnmFuncEvalInfo * ei,GnmValue const * const * argv)1205 gnumeric_combina (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1206 {
1207 gnm_float n = gnm_floor (value_get_as_float (argv[0]));
1208 gnm_float k = gnm_floor (value_get_as_float (argv[1]));
1209
1210 if (k >= 0 && n >= 0)
1211 return value_new_float (combin (n + k - 1, k));
1212
1213 return value_new_error_NUM (ei->pos);
1214 }
1215 /***************************************************************************/
1216
1217 static GnmFuncHelp const help_floor[] = {
1218 { GNM_FUNC_HELP_NAME, F_("FLOOR:nearest multiple of @{significance} whose absolute value is at most ABS(@{x})") },
1219 { GNM_FUNC_HELP_ARG, F_("x:number") },
1220 { GNM_FUNC_HELP_ARG, F_("significance:base multiple (defaults to 1 for @{x} > 0 and -1 for @{x} < 0)") },
1221 { GNM_FUNC_HELP_DESCRIPTION, F_(
1222 "FLOOR(@{x},@{significance}) is the nearest multiple of @{significance} whose absolute value is at most ABS(@{x})") },
1223 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.")},
1224 { 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).")},
1225 { GNM_FUNC_HELP_EXAMPLES, "=FLOOR(0.5)" },
1226 { GNM_FUNC_HELP_EXAMPLES, "=FLOOR(5,2)" },
1227 { GNM_FUNC_HELP_EXAMPLES, "=FLOOR(-5,-2)" },
1228 { GNM_FUNC_HELP_EXAMPLES, "=FLOOR(-5,2)" },
1229 { GNM_FUNC_HELP_SEEALSO, "CEIL,CEILING,ABS,INT,MOD" },
1230 { GNM_FUNC_HELP_END }
1231 };
1232
1233 static GnmValue *
gnumeric_floor(GnmFuncEvalInfo * ei,GnmValue const * const * argv)1234 gnumeric_floor (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1235 {
1236 gnm_float x = value_get_as_float (argv[0]);
1237 gnm_float s = argv[1] ? value_get_as_float (argv[1]) : (x > 0 ? 1 : -1);
1238
1239 if (x == 0)
1240 return value_new_int (0);
1241
1242 if (s == 0)
1243 return value_new_error_DIV0 (ei->pos);
1244
1245 if (x / s < 0)
1246 return value_new_error_NUM (ei->pos);
1247
1248 return value_new_float (gnm_fake_floor (x / s) * s);
1249 }
1250
1251 /***************************************************************************/
1252
1253 static GnmFuncHelp const help_int[] = {
1254 { GNM_FUNC_HELP_NAME, F_("INT:largest integer not larger than @{x}")},
1255 { GNM_FUNC_HELP_ARG, F_("x:number")},
1256 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
1257 { GNM_FUNC_HELP_EXAMPLES, "=INT(7.2)" },
1258 { GNM_FUNC_HELP_EXAMPLES, "=INT(-5.5)" },
1259 { GNM_FUNC_HELP_SEEALSO, "CEIL,CEILING,FLOOR,ABS,MOD"},
1260 { GNM_FUNC_HELP_END}
1261 };
1262
1263 static GnmValue *
gnumeric_int(GnmFuncEvalInfo * ei,GnmValue const * const * argv)1264 gnumeric_int (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1265 {
1266 return value_new_float (gnm_fake_floor
1267 (value_get_as_float (argv[0])));
1268 }
1269
1270 /***************************************************************************/
1271
1272 static GnmFuncHelp const help_lambertw[] = {
1273 { GNM_FUNC_HELP_NAME, F_("LAMBERTW:the Lambert W function")},
1274 { GNM_FUNC_HELP_ARG, F_("x:number")},
1275 { GNM_FUNC_HELP_ARG, F_("k:branch")},
1276 { GNM_FUNC_HELP_NOTE, F_("@{k} defaults to 0, the principal branch.") },
1277 { GNM_FUNC_HELP_NOTE, F_("@{k} must be either 0 or -1.") },
1278 { GNM_FUNC_HELP_DESCRIPTION, F_("The Lambert W function is the inverse function of x=W*exp(W). There are two (real-valued) branches: k=0 which maps [-1/e;inf) onto [-1,inf); and k=-1 which maps [-1/e;0) unto (-inf;-1].") },
1279 { GNM_FUNC_HELP_EXAMPLES, "=LAMBERTW(3)" },
1280 { GNM_FUNC_HELP_EXAMPLES, "=LAMBERTW(-1/4,-1)" },
1281 { GNM_FUNC_HELP_SEEALSO, "EXP"},
1282 { GNM_FUNC_HELP_END}
1283 };
1284
1285 static GnmValue *
gnumeric_lambertw(GnmFuncEvalInfo * ei,GnmValue const * const * argv)1286 gnumeric_lambertw (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1287 {
1288 gnm_float x = value_get_as_float (argv[0]);
1289 gnm_float k = argv[1] ? value_get_as_float (argv[1]) : 0;
1290
1291 if (k != 0 && k != -1)
1292 return value_new_error_NUM (ei->pos);
1293
1294 return value_new_float (gnm_lambert_w (x, (int)k));
1295 }
1296
1297 /***************************************************************************/
1298
1299 static GnmFuncHelp const help_log[] = {
1300 { GNM_FUNC_HELP_NAME, F_("LOG:logarithm of @{x} with base @{base}")},
1301 { GNM_FUNC_HELP_ARG, F_("x:positive number")},
1302 { GNM_FUNC_HELP_ARG, F_("base:base of the logarithm, defaults to 10")},
1303 { GNM_FUNC_HELP_NOTE, F_("@{base} must be positive and not equal to 1.") },
1304 { GNM_FUNC_HELP_NOTE, F_("If @{x} \xe2\x89\xa4 0, LOG returns #NUM! error.") },
1305 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
1306 { GNM_FUNC_HELP_EXAMPLES, "=LOG(2)" },
1307 { GNM_FUNC_HELP_EXAMPLES, "=LOG(8192,2)" },
1308 { GNM_FUNC_HELP_SEEALSO, "LN,LOG2,LOG10"},
1309 { GNM_FUNC_HELP_END}
1310 };
1311
1312 static GnmValue *
gnumeric_log(GnmFuncEvalInfo * ei,GnmValue const * const * argv)1313 gnumeric_log (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1314 {
1315 gnm_float t = value_get_as_float (argv[0]);
1316 gnm_float base = argv[1] ? value_get_as_float (argv[1]) : 10;
1317 gnm_float res;
1318
1319 if (base == 1. || base <= 0.)
1320 return value_new_error_NUM (ei->pos);
1321
1322 if (t <= 0.0)
1323 return value_new_error_NUM (ei->pos);
1324
1325 if (base == 2)
1326 res = gnm_log2 (t);
1327 else if (base == 0.5)
1328 res = -gnm_log2 (t);
1329 else if (base == 10)
1330 res = gnm_log10 (t);
1331 else
1332 res = gnm_log (t) / gnm_log (base);
1333
1334 return value_new_float (res);
1335 }
1336
1337 /***************************************************************************/
1338
1339 static GnmFuncHelp const help_ln[] = {
1340 { GNM_FUNC_HELP_NAME, F_("LN:the natural logarithm of @{x}")},
1341 { GNM_FUNC_HELP_ARG, F_("x:positive number")},
1342 { GNM_FUNC_HELP_NOTE, F_("If @{x} \xe2\x89\xa4 0, LN returns #NUM! error.") },
1343 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
1344 { GNM_FUNC_HELP_EXAMPLES, "=LN(7)" },
1345 { GNM_FUNC_HELP_SEEALSO, "EXP,LOG2,LOG10"},
1346 { GNM_FUNC_HELP_END}
1347 };
1348
1349 static GnmValue *
gnumeric_ln(GnmFuncEvalInfo * ei,GnmValue const * const * argv)1350 gnumeric_ln (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1351 {
1352 gnm_float t = value_get_as_float (argv[0]);
1353
1354 if (t <= 0.0)
1355 return value_new_error_NUM (ei->pos);
1356
1357 return value_new_float (gnm_log (t));
1358 }
1359
1360 static GnmExpr const *
gnumeric_ln_deriv(GnmFunc * func,GnmExpr const * expr,GnmEvalPos const * ep,GnmExprDeriv * info,gpointer data)1361 gnumeric_ln_deriv (GnmFunc *func,
1362 GnmExpr const *expr, GnmEvalPos const *ep,
1363 GnmExprDeriv *info, gpointer data)
1364 {
1365 GnmExpr const *deriv =
1366 gnm_expr_new_binary (gnm_expr_new_constant (value_new_int (1)),
1367 GNM_EXPR_OP_DIV,
1368 gnm_expr_copy (gnm_expr_get_func_arg (expr, 0)));
1369 return gnm_expr_deriv_chain (expr, deriv, ep, info);
1370 }
1371
1372 /***************************************************************************/
1373
1374 static GnmFuncHelp const help_ln1p[] = {
1375 { GNM_FUNC_HELP_NAME, F_("LN1P:LN(1+@{x})")},
1376 { GNM_FUNC_HELP_ARG, F_("x:positive number")},
1377 { GNM_FUNC_HELP_DESCRIPTION, F_("LN1P calculates LN(1+@{x}) but yielding a higher precision than evaluating LN(1+@{x}).")},
1378 { GNM_FUNC_HELP_NOTE, F_("If @{x} \xe2\x89\xa4 -1, LN returns #NUM! error.") },
1379 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
1380 { GNM_FUNC_HELP_EXAMPLES, "=LN1P(0.01)" },
1381 { GNM_FUNC_HELP_SEEALSO, "EXP,LN,EXPM1"},
1382 { GNM_FUNC_HELP_END}
1383 };
1384
1385 static GnmValue *
gnumeric_ln1p(GnmFuncEvalInfo * ei,GnmValue const * const * argv)1386 gnumeric_ln1p (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1387 {
1388 gnm_float t = value_get_as_float (argv[0]);
1389
1390 if (t <= -1)
1391 return value_new_error_NUM (ei->pos);
1392
1393 return value_new_float (gnm_log1p (t));
1394 }
1395
1396 /***************************************************************************/
1397
1398 static GnmFuncHelp const help_power[] = {
1399 { GNM_FUNC_HELP_NAME, F_("POWER:the value of @{x} raised to the power @{y} raised to the power of 1/@{z}")},
1400 { GNM_FUNC_HELP_ARG, F_("x:number")},
1401 { GNM_FUNC_HELP_ARG, F_("y:number")},
1402 { GNM_FUNC_HELP_ARG, F_("z:number")},
1403 { GNM_FUNC_HELP_NOTE, F_("If both @{x} and @{y} equal 0, POWER returns #NUM!") },
1404 { GNM_FUNC_HELP_NOTE, F_("If @{x} = 0 and @{y} < 0, POWER returns #DIV/0!") },
1405 { GNM_FUNC_HELP_NOTE, F_("If @{x} < 0 and @{y} is not an integer, POWER returns #NUM!") },
1406 { GNM_FUNC_HELP_NOTE, F_("@{z} defaults to 1") },
1407 { GNM_FUNC_HELP_NOTE, F_("If @{z} is not a positive integer, POWER returns #NUM!") },
1408 { GNM_FUNC_HELP_NOTE, F_("If @{x} < 0, @{y} is odd, and @{z} is even, POWER returns #NUM!") },
1409 { GNM_FUNC_HELP_EXAMPLES, "=POWER(2,7)" },
1410 { GNM_FUNC_HELP_EXAMPLES, "=POWER(3,3.141)" },
1411 { GNM_FUNC_HELP_SEEALSO, "EXP"},
1412 { GNM_FUNC_HELP_END}
1413 };
1414
1415 static GnmValue *
gnumeric_power(GnmFuncEvalInfo * ei,GnmValue const * const * argv)1416 gnumeric_power (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1417 {
1418 gnm_float x = value_get_as_float (argv[0]);
1419 gnm_float y = value_get_as_float (argv[1]);
1420 gnm_float z = argv[2] ? value_get_as_float (argv[2]) : 1;
1421
1422 if ((x > 0) || (x == 0 && y > 0) || (x < 0 && y == gnm_floor (y))) {
1423 gnm_float r = gnm_pow (x, y);
1424 gboolean z_even = gnm_fmod (z, 2.0) == 0;
1425 if (z <= 0 || z != gnm_floor (z) || (r < 0 && z_even))
1426 return value_new_error_NUM (ei->pos);
1427 if (z != 1)
1428 r = (r < 0 ? -1 : +1) * gnm_pow (gnm_abs (r), 1 / z);
1429 return value_new_float (r);
1430 }
1431
1432 if (x == 0 && y != 0)
1433 return value_new_error_DIV0 (ei->pos);
1434 else
1435 return value_new_error_NUM (ei->pos);
1436 }
1437
1438 /***************************************************************************/
1439
1440 static GnmFuncHelp const help_pochhammer[] = {
1441 { GNM_FUNC_HELP_NAME, F_("POCHHAMMER:the value of GAMMA(@{x}+@{n})/GAMMA(@{x})")},
1442 { GNM_FUNC_HELP_ARG, F_("x:number")},
1443 { GNM_FUNC_HELP_ARG, F_("n:number")},
1444 { GNM_FUNC_HELP_EXAMPLES, "=POCHHAMMER(1,5)" },
1445 { GNM_FUNC_HELP_EXAMPLES, "=POCHHAMMER(6,0.5)" },
1446 { GNM_FUNC_HELP_SEEALSO, "GAMMA"},
1447 { GNM_FUNC_HELP_END}
1448 };
1449
1450 static GnmValue *
gnumeric_pochhammer(GnmFuncEvalInfo * ei,GnmValue const * const * argv)1451 gnumeric_pochhammer (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1452 {
1453 gnm_float x = value_get_as_float (argv[0]);
1454 gnm_float n = value_get_as_float (argv[1]);
1455
1456 return value_new_float (pochhammer (x, n));
1457 }
1458
1459 /***************************************************************************/
1460
1461 static GnmFuncHelp const help_log2[] = {
1462 { GNM_FUNC_HELP_NAME, F_("LOG2:the base-2 logarithm of @{x}")},
1463 { GNM_FUNC_HELP_ARG, F_("x:positive number")},
1464 { GNM_FUNC_HELP_NOTE, F_("If @{x} \xe2\x89\xa4 0, LOG2 returns #NUM!") },
1465 { GNM_FUNC_HELP_EXAMPLES, "=LOG2(1024)" },
1466 { GNM_FUNC_HELP_SEEALSO, "EXP,LOG10,LOG"},
1467 { GNM_FUNC_HELP_END}
1468 };
1469
1470 static GnmValue *
gnumeric_log2(GnmFuncEvalInfo * ei,GnmValue const * const * argv)1471 gnumeric_log2 (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1472 {
1473 gnm_float t = value_get_as_float (argv[0]);
1474
1475 if (t <= 0.0)
1476 return value_new_error_NUM (ei->pos);
1477
1478 return value_new_float (gnm_log2 (t));
1479 }
1480
1481 /***************************************************************************/
1482
1483 static GnmFuncHelp const help_log10[] = {
1484 { GNM_FUNC_HELP_NAME, F_("LOG10:the base-10 logarithm of @{x}")},
1485 { GNM_FUNC_HELP_ARG, F_("x:positive number")},
1486 { GNM_FUNC_HELP_NOTE, F_("If @{x} \xe2\x89\xa4 0, LOG10 returns #NUM!") },
1487 { GNM_FUNC_HELP_EXAMPLES, "=LOG10(1024)" },
1488 { GNM_FUNC_HELP_SEEALSO, "EXP,LOG2,LOG"},
1489 { GNM_FUNC_HELP_END}
1490 };
1491
1492 static GnmValue *
gnumeric_log10(GnmFuncEvalInfo * ei,GnmValue const * const * argv)1493 gnumeric_log10 (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1494 {
1495 gnm_float t = value_get_as_float (argv[0]);
1496
1497 if (t <= 0.0)
1498 return value_new_error_NUM (ei->pos);
1499
1500 return value_new_float (gnm_log10 (t));
1501 }
1502
1503 /***************************************************************************/
1504
1505 static GnmFuncHelp const help_mod[] = {
1506 { GNM_FUNC_HELP_NAME, F_("MOD:the remainder of @{x} under division by @{n}")},
1507 { GNM_FUNC_HELP_ARG, F_("x:integer")},
1508 { GNM_FUNC_HELP_ARG, F_("n:integer")},
1509 { GNM_FUNC_HELP_DESCRIPTION, F_("MOD function returns the remainder when @{x} is divided by @{n}.")},
1510 { GNM_FUNC_HELP_NOTE, F_("If @{n} is 0, MOD returns #DIV/0!")},
1511 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
1512 { GNM_FUNC_HELP_EXAMPLES, "=MOD(23,7)" },
1513 { GNM_FUNC_HELP_EXAMPLES, "=MOD(23,-7)" },
1514 { GNM_FUNC_HELP_SEEALSO, "CEIL,CEILING,FLOOR,ABS,INT,ABS"},
1515 { GNM_FUNC_HELP_END}
1516 };
1517
1518 /*
1519 * MOD(-1,-3) = -1
1520 * MOD(2,-3) = -2
1521 * MOD(10.6,2) = 0.6
1522 * MOD(-10.6,2) = 1.4
1523 * MOD(10.6,-2) = -0.6
1524 * MOD(-10.6,-2) = -1.4
1525 */
1526
1527 static GnmValue *
gnumeric_mod(GnmFuncEvalInfo * ei,GnmValue const * const * argv)1528 gnumeric_mod (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1529 {
1530 gnm_float a = value_get_as_float (argv[0]);
1531 gnm_float b = value_get_as_float (argv[1]);
1532 gnm_float babs, r;
1533
1534 if (b == 0)
1535 return value_new_error_DIV0 (ei->pos);
1536
1537 babs = gnm_abs (b);
1538 r = gnm_fmod (gnm_abs (a), babs);
1539 if (r > 0) {
1540 if ((a < 0) != (b < 0))
1541 r = babs - r;
1542 if (b < 0)
1543 r = -r;
1544 }
1545
1546 return value_new_float (r);
1547 }
1548
1549 /***************************************************************************/
1550
1551 static GnmFuncHelp const help_radians[] = {
1552 { GNM_FUNC_HELP_NAME, F_("RADIANS:the number of radians equivalent to @{x} degrees")},
1553 { GNM_FUNC_HELP_ARG, F_("x:angle in degrees")},
1554 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
1555 { GNM_FUNC_HELP_EXAMPLES, "=RADIANS(180)" },
1556 { GNM_FUNC_HELP_SEEALSO, "PI,DEGREES"},
1557 { GNM_FUNC_HELP_END}
1558 };
1559
1560 static GnmValue *
gnumeric_radians(GnmFuncEvalInfo * ei,GnmValue const * const * argv)1561 gnumeric_radians (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1562 {
1563 return value_new_float ((value_get_as_float (argv[0]) * M_PIgnum) /
1564 180);
1565 }
1566
1567 /***************************************************************************/
1568
1569 static GnmFuncHelp const help_reducepi[] = {
1570 { GNM_FUNC_HELP_NAME, F_("REDUCEPI:reduce modulo Pi divided by a power of 2")},
1571 { GNM_FUNC_HELP_ARG, F_("x:number")},
1572 { GNM_FUNC_HELP_ARG, F_("e:scale")},
1573 { GNM_FUNC_HELP_ARG, F_("q:get lower bits of quotient, defaults to FALSE")},
1574 { GNM_FUNC_HELP_EXAMPLES, "=REDUCEPI(10,1)" },
1575 { 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.")},
1576 { 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.")},
1577 { GNM_FUNC_HELP_SEEALSO, "PI"},
1578 { GNM_FUNC_HELP_END}
1579 };
1580
1581 static GnmValue *
gnumeric_reducepi(GnmFuncEvalInfo * ei,GnmValue const * const * argv)1582 gnumeric_reducepi (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1583 {
1584 gnm_float x = value_get_as_float (argv[0]);
1585 int e = value_get_as_int (argv[1]);
1586 gboolean q = argv[2] ? value_get_as_checked_bool (argv[2]) : FALSE;
1587 int j;
1588 gnm_float xr;
1589
1590 if (e < -1 || e > 7)
1591 return value_new_error_VALUE (ei->pos);
1592
1593 xr = gnm_reduce_pi (x, (int)e, &j);
1594 return q ? value_new_int (j) : value_new_float (xr);
1595 }
1596
1597 /***************************************************************************/
1598
1599 static GnmFuncHelp const help_sin[] = {
1600 { GNM_FUNC_HELP_NAME, F_("SIN:the sine of @{x}")},
1601 { GNM_FUNC_HELP_ARG, F_("x:angle in radians")},
1602 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
1603 { GNM_FUNC_HELP_EXAMPLES, "=SIN(0.5)" },
1604 { GNM_FUNC_HELP_SEEALSO, "COS,TAN,CSC,SEC,SINH,COSH,TANH,RADIANS,DEGREES" },
1605 { GNM_FUNC_HELP_EXTREF, F_("wolfram:Sine.html") },
1606 { GNM_FUNC_HELP_EXTREF, F_("wiki:en:Trigonometric_functions") },
1607 { GNM_FUNC_HELP_END }
1608 };
1609
1610 static GnmValue *
gnumeric_sin(GnmFuncEvalInfo * ei,GnmValue const * const * argv)1611 gnumeric_sin (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1612 {
1613 return value_new_float (gnm_sin (value_get_as_float (argv[0])));
1614 }
1615
1616 /***************************************************************************/
1617
1618 static GnmFuncHelp const help_sinpi[] = {
1619 { GNM_FUNC_HELP_NAME, F_("SINPI:the sine of Pi*@{x}")},
1620 { GNM_FUNC_HELP_ARG, F_("x:number of half turns")},
1621 { GNM_FUNC_HELP_EXAMPLES, "=SINPI(0.5)" },
1622 { GNM_FUNC_HELP_EXAMPLES, "=SINPI(1)" },
1623 { GNM_FUNC_HELP_SEEALSO, "SIN" },
1624 { GNM_FUNC_HELP_END }
1625 };
1626
1627 static GnmValue *
gnumeric_sinpi(GnmFuncEvalInfo * ei,GnmValue const * const * argv)1628 gnumeric_sinpi (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1629 {
1630 return value_new_float (gnm_sinpi (value_get_as_float (argv[0])));
1631 }
1632
1633 /***************************************************************************/
1634
1635 static GnmFuncHelp const help_csc[] = {
1636 { GNM_FUNC_HELP_NAME, F_("CSC:the cosecant of @{x}")},
1637 { GNM_FUNC_HELP_ARG, F_("x:angle in radians")},
1638 { GNM_FUNC_HELP_EXCEL, F_("This function is not Excel compatible.") },
1639 { GNM_FUNC_HELP_ODF, F_("This function is OpenFormula compatible.") },
1640 { GNM_FUNC_HELP_EXAMPLES, "=CSC(0.5)" },
1641 { GNM_FUNC_HELP_SEEALSO, "SIN,COS,TAN,SEC,SINH,COSH,TANH,RADIANS,DEGREES" },
1642 { GNM_FUNC_HELP_EXTREF, F_("wolfram:Cosecant.html") },
1643 { GNM_FUNC_HELP_EXTREF, F_("wiki:en:Trigonometric_functions") },
1644 { GNM_FUNC_HELP_END }
1645 };
1646
1647 static GnmValue *
gnumeric_csc(GnmFuncEvalInfo * ei,GnmValue const * const * argv)1648 gnumeric_csc (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1649 {
1650 return value_new_float (1./gnm_sin (value_get_as_float (argv[0])));
1651 }
1652
1653 /***************************************************************************/
1654
1655 static GnmFuncHelp const help_csch[] = {
1656 { GNM_FUNC_HELP_NAME, F_("CSCH:the hyperbolic cosecant of @{x}")},
1657 { GNM_FUNC_HELP_ARG, F_("x:number")},
1658 { GNM_FUNC_HELP_EXCEL, F_("This function is not Excel compatible.") },
1659 { GNM_FUNC_HELP_ODF, F_("This function is OpenFormula compatible.") },
1660 { GNM_FUNC_HELP_EXAMPLES, "=CSCH(0.5)" },
1661 { GNM_FUNC_HELP_SEEALSO, "SIN,COS,TAN,CSC,SEC,SINH,COSH,TANH" },
1662 { GNM_FUNC_HELP_EXTREF, F_("wolfram:HyperbolicCosecant.html") },
1663 { GNM_FUNC_HELP_EXTREF, F_("wiki:en:Hyperbolic_function") },
1664 { GNM_FUNC_HELP_END }
1665 };
1666
1667 static GnmValue *
gnumeric_csch(GnmFuncEvalInfo * ei,GnmValue const * const * argv)1668 gnumeric_csch (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1669 {
1670 return value_new_float (1./gnm_sinh (value_get_as_float (argv[0])));
1671 }
1672
1673 /***************************************************************************/
1674
1675 static GnmFuncHelp const help_sec[] = {
1676 { GNM_FUNC_HELP_NAME, F_("SEC:Secant")},
1677 { GNM_FUNC_HELP_ARG, F_("x:angle in radians")},
1678 { GNM_FUNC_HELP_EXCEL, F_("This function is not Excel compatible.") },
1679 { GNM_FUNC_HELP_ODF, F_("SEC(@{x}) is exported to OpenFormula as 1/COS(@{x}).") },
1680 { GNM_FUNC_HELP_EXAMPLES, "=SEC(0.5)" },
1681 { GNM_FUNC_HELP_SEEALSO, "SIN,COS,TAN,CSC,SINH,COSH,TANH,RADIANS,DEGREES" },
1682 { GNM_FUNC_HELP_EXTREF, F_("wolfram:Secant.html") },
1683 { GNM_FUNC_HELP_EXTREF, F_("wiki:en:Trigonometric_functions") },
1684 { GNM_FUNC_HELP_END }
1685 };
1686
1687 static GnmValue *
gnumeric_sec(GnmFuncEvalInfo * ei,GnmValue const * const * argv)1688 gnumeric_sec (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1689 {
1690 return value_new_float (1./gnm_cos (value_get_as_float (argv[0])));
1691 }
1692
1693 /***************************************************************************/
1694
1695 static GnmFuncHelp const help_sech[] = {
1696 { GNM_FUNC_HELP_NAME, F_("SECH:the hyperbolic secant of @{x}")},
1697 { GNM_FUNC_HELP_ARG, F_("x:number")},
1698 { GNM_FUNC_HELP_EXCEL, F_("This function is not Excel compatible.") },
1699 { GNM_FUNC_HELP_ODF, F_("SECH(@{x}) is exported to OpenFormula as 1/COSH(@{x}).") },
1700 { GNM_FUNC_HELP_EXAMPLES, "=SECH(0.5)" },
1701 { GNM_FUNC_HELP_SEEALSO, "SIN,COS,TAN,CSC,SEC,SINH,COSH,TANH" },
1702 { GNM_FUNC_HELP_EXTREF, F_("wolfram:HyperbolicSecant.html") },
1703 { GNM_FUNC_HELP_EXTREF, F_("wiki:en:Hyperbolic_function") },
1704 { GNM_FUNC_HELP_END }
1705 };
1706
1707 static GnmValue *
gnumeric_sech(GnmFuncEvalInfo * ei,GnmValue const * const * argv)1708 gnumeric_sech (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1709 {
1710 return value_new_float (1./gnm_cosh (value_get_as_float (argv[0])));
1711 }
1712 /***************************************************************************/
1713 static GnmFuncHelp const help_sinh[] = {
1714 { GNM_FUNC_HELP_NAME, F_("SINH:the hyperbolic sine of @{x}")},
1715 { GNM_FUNC_HELP_ARG, F_("x:number")},
1716 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
1717 { GNM_FUNC_HELP_EXAMPLES, "=SINH(0.1)" },
1718 { GNM_FUNC_HELP_EXAMPLES, "=SINH(-0.1)" },
1719 { GNM_FUNC_HELP_SEEALSO, "SIN,COSH,ASINH"},
1720 { GNM_FUNC_HELP_END}
1721 };
1722
1723 static GnmValue *
gnumeric_sinh(GnmFuncEvalInfo * ei,GnmValue const * const * argv)1724 gnumeric_sinh (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1725 {
1726 return value_new_float (gnm_sinh (value_get_as_float (argv[0])));
1727 }
1728
1729 /***************************************************************************/
1730
1731 static GnmFuncHelp const help_sqrt[] = {
1732 { GNM_FUNC_HELP_NAME, F_("SQRT:square root of @{x}")},
1733 { GNM_FUNC_HELP_ARG, F_("x:non-negative number")},
1734 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
1735 { GNM_FUNC_HELP_NOTE, F_("If @{x} is negative, SQRT returns #NUM!")},
1736 { GNM_FUNC_HELP_EXAMPLES, "=SQRT(2)"},
1737 { GNM_FUNC_HELP_SEEALSO, "POWER"},
1738 { GNM_FUNC_HELP_END}
1739 };
1740
1741 static GnmValue *
gnumeric_sqrt(GnmFuncEvalInfo * ei,GnmValue const * const * argv)1742 gnumeric_sqrt (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1743 {
1744 gnm_float x = value_get_as_float (argv[0]);
1745 if (x < 0)
1746 return value_new_error_NUM (ei->pos);
1747
1748 return value_new_float (gnm_sqrt (x));
1749 }
1750
1751 /***************************************************************************/
1752
1753 static GnmFuncHelp const help_suma[] = {
1754 { GNM_FUNC_HELP_NAME, F_("SUMA:sum of all values and cells referenced")},
1755 { GNM_FUNC_HELP_ARG, F_("area0:first cell area")},
1756 { GNM_FUNC_HELP_ARG, F_("area1:second cell area")},
1757 { FUNCTION_A_DESC },
1758 { GNM_FUNC_HELP_EXAMPLES, "=SUMA(11,TRUE,FALSE,12)"},
1759 { GNM_FUNC_HELP_SEEALSO, "AVERAGE,SUM,COUNT"},
1760 { GNM_FUNC_HELP_END}
1761 };
1762
1763
1764 static GnmValue *
gnumeric_suma(GnmFuncEvalInfo * ei,int argc,GnmExprConstPtr const * argv)1765 gnumeric_suma (GnmFuncEvalInfo *ei, int argc, GnmExprConstPtr const *argv)
1766 {
1767 return float_range_function (argc, argv, ei,
1768 gnm_range_sum,
1769 COLLECT_ZERO_STRINGS |
1770 COLLECT_ZEROONE_BOOLS |
1771 COLLECT_IGNORE_BLANKS,
1772 GNM_ERROR_VALUE);
1773 }
1774
1775 /***************************************************************************/
1776
1777 static GnmFuncHelp const help_sumsq[] = {
1778 { GNM_FUNC_HELP_NAME, F_("SUMSQ:sum of the squares of all values and cells referenced")},
1779 { GNM_FUNC_HELP_ARG, F_("area0:first cell area")},
1780 { GNM_FUNC_HELP_ARG, F_("area1:second cell area")},
1781 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
1782 { GNM_FUNC_HELP_EXAMPLES, "=SUMSQ(11,TRUE,FALSE,12)"},
1783 { GNM_FUNC_HELP_SEEALSO, "SUM,COUNT"},
1784 { GNM_FUNC_HELP_END}
1785 };
1786
1787 static GnmValue *
gnumeric_sumsq(GnmFuncEvalInfo * ei,int argc,GnmExprConstPtr const * argv)1788 gnumeric_sumsq (GnmFuncEvalInfo *ei, int argc, GnmExprConstPtr const *argv)
1789 {
1790 return float_range_function (argc, argv, ei,
1791 gnm_range_sumsq,
1792 COLLECT_IGNORE_STRINGS |
1793 COLLECT_IGNORE_BOOLS |
1794 COLLECT_IGNORE_BLANKS,
1795 GNM_ERROR_VALUE);
1796 }
1797
1798 // Construct an equivalend expression
1799 static GnmExpr const *
gnumeric_sumsq_equiv(GnmExpr const * expr,GnmEvalPos const * ep,GnmExprDeriv * info)1800 gnumeric_sumsq_equiv (GnmExpr const *expr, GnmEvalPos const *ep,
1801 GnmExprDeriv *info)
1802 {
1803 GnmExprList *l, *args;
1804 GnmFunc *fsum = gnm_func_lookup ("SUM", NULL);
1805
1806 if (!fsum) return NULL;
1807
1808 args = gnm_expr_deriv_collect (expr, ep, info);
1809 for (l = args; l; l = l->next) {
1810 GnmExpr const *e = l->data;
1811 GnmExpr const *ee = gnm_expr_new_binary
1812 (e,
1813 GNM_EXPR_OP_EXP,
1814 gnm_expr_new_constant (value_new_int (2)));
1815 l->data = (gpointer)ee;
1816 }
1817
1818 return gnm_expr_new_funcall (fsum, args);
1819 }
1820
1821 static GnmExpr const *
gnumeric_sumsq_deriv(GnmFunc * func,GnmExpr const * expr,GnmEvalPos const * ep,GnmExprDeriv * info)1822 gnumeric_sumsq_deriv (GnmFunc *func,
1823 GnmExpr const *expr, GnmEvalPos const *ep,
1824 GnmExprDeriv *info)
1825 {
1826 GnmExpr const *sqsum = gnumeric_sumsq_equiv (expr, ep, info);
1827 if (sqsum) {
1828 GnmExpr const *res = gnm_expr_deriv (sqsum, ep, info);
1829 gnm_expr_free (sqsum);
1830 return res;
1831 } else
1832 return NULL;
1833 }
1834
1835 /***************************************************************************/
1836
1837 static GnmFuncHelp const help_multinomial[] = {
1838 { GNM_FUNC_HELP_NAME, F_("MULTINOMIAL:multinomial coefficient (@{x1}+\xe2\x8b\xaf+@{xn}) choose (@{x1},\xe2\x80\xa6,@{xn})")},
1839 { GNM_FUNC_HELP_ARG, F_("x1:first number")},
1840 { GNM_FUNC_HELP_ARG, F_("x2:second number")},
1841 { GNM_FUNC_HELP_ARG, F_("xn:nth number")},
1842 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
1843 { GNM_FUNC_HELP_EXAMPLES, "=MULTINOMIAL(2,3,4)"},
1844 { GNM_FUNC_HELP_SEEALSO, "COMBIN,SUM"},
1845 { GNM_FUNC_HELP_EXTREF, F_("wiki:en:Multinomial_theorem") },
1846 { GNM_FUNC_HELP_END}
1847 };
1848
1849 static GnmValue *
gnumeric_multinomial(GnmFuncEvalInfo * ei,int argc,GnmExprConstPtr const * argv)1850 gnumeric_multinomial (GnmFuncEvalInfo *ei, int argc, GnmExprConstPtr const *argv)
1851 {
1852 return float_range_function (argc, argv, ei,
1853 gnm_range_multinomial,
1854 COLLECT_IGNORE_STRINGS |
1855 COLLECT_IGNORE_BOOLS |
1856 COLLECT_IGNORE_BLANKS,
1857 GNM_ERROR_NUM);
1858 }
1859
1860 /***************************************************************************/
1861
1862 static GnmFuncHelp const help_g_product[] = {
1863 { GNM_FUNC_HELP_NAME, F_("G_PRODUCT:product of all the values and cells referenced")},
1864 { GNM_FUNC_HELP_ARG, F_("x1:number")},
1865 { GNM_FUNC_HELP_ARG, F_("x2:number")},
1866 { GNM_FUNC_HELP_NOTE, F_("Empty cells are ignored and the empty product is 1.")},
1867 { GNM_FUNC_HELP_EXAMPLES, "=G_PRODUCT(2,5,9)"},
1868 { GNM_FUNC_HELP_SEEALSO, "SUM,COUNT"},
1869 { GNM_FUNC_HELP_END}
1870 };
1871
1872 static GnmValue *
gnumeric_g_product(GnmFuncEvalInfo * ei,int argc,GnmExprConstPtr const * argv)1873 gnumeric_g_product (GnmFuncEvalInfo *ei, int argc, GnmExprConstPtr const *argv)
1874 {
1875 return float_range_function (argc, argv, ei,
1876 gnm_range_product,
1877 COLLECT_IGNORE_STRINGS |
1878 COLLECT_IGNORE_BOOLS |
1879 COLLECT_IGNORE_BLANKS,
1880 GNM_ERROR_VALUE);
1881 }
1882
1883 /***************************************************************************/
1884
1885 static GnmFuncHelp const help_tan[] = {
1886 { GNM_FUNC_HELP_NAME, F_("TAN:the tangent of @{x}")},
1887 { GNM_FUNC_HELP_ARG, F_("x:angle in radians")},
1888 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
1889 { GNM_FUNC_HELP_EXAMPLES, "=TAN(3)"},
1890 { GNM_FUNC_HELP_SEEALSO, "TANH,COS,COSH,SIN,SINH,DEGREES,RADIANS"},
1891 { GNM_FUNC_HELP_END}
1892 };
1893
1894 static GnmValue *
gnumeric_tan(GnmFuncEvalInfo * ei,GnmValue const * const * argv)1895 gnumeric_tan (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1896 {
1897 return value_new_float (gnm_tan (value_get_as_float (argv[0])));
1898 }
1899
1900 /***************************************************************************/
1901
1902 static GnmFuncHelp const help_tanpi[] = {
1903 { GNM_FUNC_HELP_NAME, F_("TANPI:the tangent of Pi*@{x}")},
1904 { GNM_FUNC_HELP_ARG, F_("x:number of half turns")},
1905 { GNM_FUNC_HELP_EXAMPLES, "=TANPI(1)" },
1906 { GNM_FUNC_HELP_EXAMPLES, "=TANPI(0.25)" },
1907 { GNM_FUNC_HELP_SEEALSO, "TAN" },
1908 { GNM_FUNC_HELP_END }
1909 };
1910
1911 static GnmValue *
gnumeric_tanpi(GnmFuncEvalInfo * ei,GnmValue const * const * argv)1912 gnumeric_tanpi (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1913 {
1914 return value_new_float (gnm_tanpi (value_get_as_float (argv[0])));
1915 }
1916
1917 /***************************************************************************/
1918 static GnmFuncHelp const help_tanh[] = {
1919 { GNM_FUNC_HELP_NAME, F_("TANH:the hyperbolic tangent of @{x}")},
1920 { GNM_FUNC_HELP_ARG, F_("x:number")},
1921 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
1922 { GNM_FUNC_HELP_EXAMPLES, "=TANH(2)"},
1923 { GNM_FUNC_HELP_SEEALSO, "TAN,SIN,SINH,COS,COSH"},
1924 { GNM_FUNC_HELP_END}
1925 };
1926
1927 static GnmValue *
gnumeric_tanh(GnmFuncEvalInfo * ei,GnmValue const * const * argv)1928 gnumeric_tanh (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1929 {
1930 return value_new_float (gnm_tanh (value_get_as_float (argv[0])));
1931 }
1932
1933 /***************************************************************************/
1934
1935 static GnmFuncHelp const help_pi[] = {
1936 { GNM_FUNC_HELP_NAME, F_("PI:the constant " "\360\235\234\213")},
1937 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible, but it "
1938 "returns " "\360\235\234\213" " with a better "
1939 "precision.") },
1940 { GNM_FUNC_HELP_EXAMPLES, "=PI()" },
1941 { GNM_FUNC_HELP_SEEALSO, "SQRTPI"},
1942 { GNM_FUNC_HELP_END}
1943 };
1944
1945 static GnmValue *
gnumeric_pi(GnmFuncEvalInfo * ei,GnmValue const * const * argv)1946 gnumeric_pi (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1947 {
1948 return value_new_float (M_PIgnum);
1949 }
1950
1951 /***************************************************************************/
1952
1953 static GnmFuncHelp const help_trunc[] = {
1954 { GNM_FUNC_HELP_NAME, F_("TRUNC:@{x} truncated to @{d} digits")},
1955 { GNM_FUNC_HELP_ARG, F_("x:number")},
1956 { GNM_FUNC_HELP_ARG, F_("d:non-negative integer, defaults to 0")},
1957 { 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.")},
1958 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
1959 { GNM_FUNC_HELP_EXAMPLES, "=TRUNC(35.12)"},
1960 { GNM_FUNC_HELP_EXAMPLES, "=TRUNC(43.15,1)"},
1961 { GNM_FUNC_HELP_SEEALSO, "INT"},
1962 { GNM_FUNC_HELP_END}
1963 };
1964
1965 static GnmValue *
gnumeric_trunc(GnmFuncEvalInfo * ei,GnmValue const * const * argv)1966 gnumeric_trunc (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
1967 {
1968 gnm_float number = value_get_as_float (argv[0]);
1969 gnm_float digits = argv[1] ? value_get_as_float (argv[1]) : 0;
1970
1971 if (digits >= 0) {
1972 if (digits <= GNM_MAX_EXP) {
1973 gnm_float p10 = gnm_pow10 ((int)digits);
1974 number = gnm_fake_trunc (number * p10) / p10;
1975 }
1976 } else {
1977 if (digits >= GNM_MIN_EXP) {
1978 /* Keep p10 integer. */
1979 gnm_float p10 = gnm_pow10 ((int)-digits);
1980 number = gnm_fake_trunc (number / p10) * p10;
1981 } else
1982 number = 0;
1983 }
1984
1985 return value_new_float (number);
1986 }
1987
1988 /***************************************************************************/
1989
1990 static GnmFuncHelp const help_even[] = {
1991 { GNM_FUNC_HELP_NAME, F_("EVEN:@{x} rounded away from 0 to the next even integer")},
1992 { GNM_FUNC_HELP_ARG, F_("x:number")},
1993 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
1994 { GNM_FUNC_HELP_EXAMPLES, "=EVEN(5.4)"},
1995 { GNM_FUNC_HELP_EXAMPLES, "=EVEN(-5.4)"},
1996 { GNM_FUNC_HELP_SEEALSO, "ODD"},
1997 { GNM_FUNC_HELP_END}
1998 };
1999
2000 static GnmValue *
gnumeric_even(GnmFuncEvalInfo * ei,GnmValue const * const * argv)2001 gnumeric_even (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
2002 {
2003 gnm_float number, ceiled;
2004 int sign = 1;
2005
2006 number = value_get_as_float (argv[0]);
2007 if (number < 0) {
2008 sign = -1;
2009 number = -number;
2010 }
2011 ceiled = gnm_ceil (number);
2012 if (gnm_fmod (ceiled, 2) == 0)
2013 if (number > ceiled)
2014 number = sign * (ceiled + 2);
2015 else
2016 number = sign * ceiled;
2017 else
2018 number = sign * (ceiled + 1);
2019
2020 return value_new_float (number);
2021 }
2022
2023 /***************************************************************************/
2024
2025 static GnmFuncHelp const help_odd[] = {
2026 { GNM_FUNC_HELP_NAME, F_("ODD:@{x} rounded away from 0 to the next odd integer")},
2027 { GNM_FUNC_HELP_ARG, F_("x:number")},
2028 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
2029 { GNM_FUNC_HELP_EXAMPLES, "=ODD(5.4)"},
2030 { GNM_FUNC_HELP_EXAMPLES, "=ODD(-5.4)"},
2031 { GNM_FUNC_HELP_SEEALSO, "EVEN"},
2032 { GNM_FUNC_HELP_END}
2033 };
2034
2035 static GnmValue *
gnumeric_odd(GnmFuncEvalInfo * ei,GnmValue const * const * argv)2036 gnumeric_odd (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
2037 {
2038 gnm_float number, ceiled;
2039 int sign = 1;
2040
2041 number = value_get_as_float (argv[0]);
2042 if (number < 0) {
2043 sign = -1;
2044 number = -number;
2045 }
2046 ceiled = gnm_ceil (number);
2047 if (gnm_fmod (ceiled, 2) == 1)
2048 if (number > ceiled)
2049 number = sign * (ceiled + 2);
2050 else
2051 number = sign * ceiled;
2052 else
2053 number = sign * (ceiled + 1);
2054
2055 return value_new_float (number);
2056 }
2057
2058 /***************************************************************************/
2059
2060 static GnmFuncHelp const help_factdouble[] = {
2061 { GNM_FUNC_HELP_NAME, F_("FACTDOUBLE:double factorial")},
2062 { GNM_FUNC_HELP_ARG, F_("x:non-negative integer")},
2063 { GNM_FUNC_HELP_DESCRIPTION, F_("FACTDOUBLE function returns the double factorial @{x}!!")},
2064 { GNM_FUNC_HELP_NOTE, F_("If @{x} is not an integer, it is truncated. If @{x} is negative, FACTDOUBLE returns #NUM!") },
2065 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
2066 { GNM_FUNC_HELP_EXAMPLES, "=FACTDOUBLE(5)"},
2067 { GNM_FUNC_HELP_SEEALSO, "FACT"},
2068 { GNM_FUNC_HELP_END}
2069 };
2070
2071 static GnmValue *
gnumeric_factdouble(GnmFuncEvalInfo * ei,GnmValue const * const * argv)2072 gnumeric_factdouble (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
2073
2074 {
2075 gnm_float number = value_get_as_float (argv[0]);
2076 int inumber, n;
2077 gnm_float res;
2078
2079 if (number < 0)
2080 return value_new_error_NUM (ei->pos);
2081
2082 inumber = (int)MIN (number, (gnm_float)INT_MAX);
2083 n = (inumber + 1) / 2;
2084
2085 if (inumber & 1) {
2086 gnm_float lres = gnm_lgamma (n + 0.5) + n * M_LN2gnum;
2087 /* Round as the result ought to be integer. */
2088 res = gnm_floor (0.5 + gnm_exp (lres) / gnm_sqrt (M_PIgnum));
2089 } else
2090 res = gnm_fact (n) * gnm_pow2 (n);
2091
2092 return value_new_float (res);
2093 }
2094
2095 /***************************************************************************/
2096
2097 static GnmFuncHelp const help_fib[] = {
2098 { GNM_FUNC_HELP_NAME, F_("FIB:Fibonacci numbers")},
2099 { GNM_FUNC_HELP_ARG, F_("n:positive integer")},
2100 { GNM_FUNC_HELP_DESCRIPTION, F_("FIB(@{n}) is the @{n}th Fibonacci number.")},
2101 { GNM_FUNC_HELP_NOTE, F_("If @{n} is not an integer, it is truncated. If it is negative or zero FIB returns #NUM!") },
2102 { GNM_FUNC_HELP_EXAMPLES, "=FIB(23)"},
2103 { GNM_FUNC_HELP_END}
2104 };
2105
2106 static GnmValue *
gnumeric_fib(GnmFuncEvalInfo * ei,GnmValue const * const * argv)2107 gnumeric_fib (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
2108
2109 {
2110 static int fibs[47];
2111 static int fib_count = G_N_ELEMENTS (fibs);
2112 static gboolean inited = FALSE;
2113 gnm_float n = gnm_floor (value_get_as_float (argv[0]));
2114
2115 if (n <= 0)
2116 return value_new_error_NUM (ei->pos);
2117
2118 if (n < fib_count) {
2119 if (!inited) {
2120 int i;
2121 fibs[1] = fibs[2] = 1;
2122 for (i = 3; i < fib_count; i++)
2123 fibs[i] = fibs[i - 1] + fibs[i - 2];
2124 inited = TRUE;
2125 }
2126 return value_new_int (fibs[(int)n]);
2127 } else {
2128 gnm_float s5 = gnm_sqrt (5.0);
2129 gnm_float r1 = (1 + s5) / 2;
2130 gnm_float r2 = (1 - s5) / 2;
2131 /* Use the Binet form. */
2132 return value_new_float ((gnm_pow (r1, n) - gnm_pow (r2, n)) / s5);
2133 }
2134 }
2135
2136 /***************************************************************************/
2137
2138 static GnmFuncHelp const help_quotient[] = {
2139 { GNM_FUNC_HELP_NAME, F_("QUOTIENT:integer portion of a division")},
2140 { GNM_FUNC_HELP_ARG, F_("numerator:integer")},
2141 { GNM_FUNC_HELP_ARG, F_("denominator:non-zero integer")},
2142 { GNM_FUNC_HELP_DESCRIPTION, F_("QUOTIENT yields the integer portion of the division @{numerator}/@{denominator}.\n"
2143 "QUOTIENT (@{numerator},@{denominator})\xe2\xa8\x89@{denominator}+MOD(@{numerator},@{denominator})=@{numerator}")},
2144 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
2145 { GNM_FUNC_HELP_EXAMPLES, "=QUOTIENT(23,5)"},
2146 { GNM_FUNC_HELP_SEEALSO, "MOD"},
2147 { GNM_FUNC_HELP_END}
2148 };
2149
2150
2151 static GnmValue *
gnumeric_quotient(GnmFuncEvalInfo * ei,GnmValue const * const * argv)2152 gnumeric_quotient (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
2153 {
2154 gnm_float num = value_get_as_float (argv[0]);
2155 gnm_float den = value_get_as_float (argv[1]);
2156
2157 if (den == 0)
2158 return value_new_error_DIV0 (ei->pos);
2159 else
2160 return value_new_float (gnm_trunc (num / den));
2161 }
2162
2163 /***************************************************************************/
2164
2165 static GnmFuncHelp const help_sign[] = {
2166 { GNM_FUNC_HELP_NAME, F_("SIGN:sign of @{x}")},
2167 { GNM_FUNC_HELP_ARG, F_("x:number")},
2168 { GNM_FUNC_HELP_DESCRIPTION, F_("SIGN returns 1 if the @{x} is positive and it returns -1 if @{x} is negative.")},
2169 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
2170 { GNM_FUNC_HELP_EXAMPLES, "=SIGN(3)"},
2171 { GNM_FUNC_HELP_EXAMPLES, "=SIGN(-3)"},
2172 { GNM_FUNC_HELP_EXAMPLES, "=SIGN(0)"},
2173 { GNM_FUNC_HELP_SEEALSO, "ABS"},
2174 { GNM_FUNC_HELP_END}
2175 };
2176
2177 static GnmValue *
gnumeric_sign(GnmFuncEvalInfo * ei,GnmValue const * const * argv)2178 gnumeric_sign (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
2179 {
2180 gnm_float n = value_get_as_float (argv[0]);
2181
2182 if (n > 0)
2183 return value_new_int (1);
2184 else if (n == 0)
2185 return value_new_int (0);
2186 else
2187 return value_new_int (-1);
2188 }
2189
2190 /***************************************************************************/
2191
2192 static GnmFuncHelp const help_sqrtpi[] = {
2193 { GNM_FUNC_HELP_NAME, F_("SQRTPI:the square root of @{x} times "
2194 "\360\235\234\213")},
2195 { GNM_FUNC_HELP_ARG, F_("x:non-negative number")},
2196 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
2197 { GNM_FUNC_HELP_EXAMPLES, "=SQRTPI(2)"},
2198 { GNM_FUNC_HELP_SEEALSO, "PI"},
2199 { GNM_FUNC_HELP_END}
2200 };
2201
2202 static GnmValue *
gnumeric_sqrtpi(GnmFuncEvalInfo * ei,GnmValue const * const * argv)2203 gnumeric_sqrtpi (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
2204 {
2205 gnm_float n = value_get_as_float (argv[0]);
2206
2207 if (n < 0)
2208 return value_new_error_NUM (ei->pos);
2209
2210 return value_new_float (gnm_sqrt (M_PIgnum * n));
2211 }
2212
2213 /***************************************************************************/
2214
2215 static GnmFuncHelp const help_rounddown[] = {
2216 { GNM_FUNC_HELP_NAME, F_("ROUNDDOWN:@{x} rounded towards 0")},
2217 { GNM_FUNC_HELP_ARG, F_("x:number")},
2218 { GNM_FUNC_HELP_ARG, F_("d:integer, defaults to 0")},
2219 { GNM_FUNC_HELP_DESCRIPTION, F_("If @{d} is greater than zero, @{x} is rounded toward 0 to the given number of digits.\n"
2220 "If @{d} is zero, @{x} is rounded toward 0 to the next integer.\n"
2221 "If @{d} is less than zero, @{x} is rounded toward 0 to the left of the decimal point")},
2222 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
2223 { GNM_FUNC_HELP_EXAMPLES, "=ROUNDDOWN(5.5)"},
2224 { GNM_FUNC_HELP_EXAMPLES, "=ROUNDDOWN(-3.3)"},
2225 { GNM_FUNC_HELP_EXAMPLES, "=ROUNDDOWN(1501.15,1)"},
2226 { GNM_FUNC_HELP_EXAMPLES, "=ROUNDDOWN(1501.15,-2)"},
2227 { GNM_FUNC_HELP_SEEALSO, "ROUND,ROUNDUP"},
2228 { GNM_FUNC_HELP_END}
2229 };
2230
2231 static GnmValue *
gnumeric_rounddown(GnmFuncEvalInfo * ei,GnmValue const * const * argv)2232 gnumeric_rounddown (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
2233 {
2234 return gnumeric_trunc (ei, argv);
2235 }
2236
2237 /***************************************************************************/
2238
2239 static GnmFuncHelp const help_round[] = {
2240 { GNM_FUNC_HELP_NAME, F_("ROUND:rounded @{x}")},
2241 { GNM_FUNC_HELP_ARG, F_("x:number")},
2242 { GNM_FUNC_HELP_ARG, F_("d:integer, defaults to 0")},
2243 { GNM_FUNC_HELP_DESCRIPTION, F_("If @{d} is greater than zero, @{x} is rounded to the given number of digits.\n"
2244 "If @{d} is zero, @{x} is rounded to the next integer.\n"
2245 "If @{d} is less than zero, @{x} is rounded to the left of the decimal point")},
2246 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
2247 { GNM_FUNC_HELP_EXAMPLES, "=ROUND(5.5)"},
2248 { GNM_FUNC_HELP_EXAMPLES, "=ROUND(-3.3)"},
2249 { GNM_FUNC_HELP_EXAMPLES, "=ROUND(1501.15,1)"},
2250 { GNM_FUNC_HELP_EXAMPLES, "=ROUND(1501.15,-2)"},
2251 { GNM_FUNC_HELP_SEEALSO, "ROUNDDOWN,ROUNDUP"},
2252 { GNM_FUNC_HELP_END}
2253 };
2254
2255 static GnmValue *
gnumeric_round(GnmFuncEvalInfo * ei,GnmValue const * const * argv)2256 gnumeric_round (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
2257 {
2258 gnm_float number = value_get_as_float (argv[0]);
2259 gnm_float digits = argv[1] ? value_get_as_float (argv[1]) : 0;
2260
2261 if (digits >= 0) {
2262 if (digits <= GNM_MAX_EXP) {
2263 gnm_float p10 = gnm_pow10 ((int)digits);
2264 number = gnm_fake_round (number * p10) / p10;
2265 }
2266 } else {
2267 if (digits >= GNM_MIN_EXP) {
2268 /* Keep p10 integer. */
2269 gnm_float p10 = gnm_pow10 ((int)-digits);
2270 number = gnm_fake_round (number / p10) * p10;
2271 } else
2272 number = 0;
2273 }
2274
2275 return value_new_float (number);
2276 }
2277
2278 /***************************************************************************/
2279
2280 static GnmFuncHelp const help_roundup[] = {
2281 { GNM_FUNC_HELP_NAME, F_("ROUNDUP:@{x} rounded away from 0")},
2282 { GNM_FUNC_HELP_ARG, F_("x:number")},
2283 { GNM_FUNC_HELP_ARG, F_("d:integer, defaults to 0")},
2284 { GNM_FUNC_HELP_DESCRIPTION, F_("If @{d} is greater than zero, @{x} is rounded away from 0 to the given number of digits.\n"
2285 "If @{d} is zero, @{x} is rounded away from 0 to the next integer.\n"
2286 "If @{d} is less than zero, @{x} is rounded away from 0 to the left of the decimal point")},
2287 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
2288 { GNM_FUNC_HELP_EXAMPLES, "=ROUNDUP(5.5)"},
2289 { GNM_FUNC_HELP_EXAMPLES, "=ROUNDUP(-3.3)"},
2290 { GNM_FUNC_HELP_EXAMPLES, "=ROUNDUP(1501.15,1)"},
2291 { GNM_FUNC_HELP_EXAMPLES, "=ROUNDUP(1501.15,-2)"},
2292 { GNM_FUNC_HELP_SEEALSO, "ROUND,ROUNDDOWN,INT"},
2293 { GNM_FUNC_HELP_END}
2294 };
2295
2296 static gnm_float
gnm_fake_roundup(gnm_float x)2297 gnm_fake_roundup (gnm_float x)
2298 {
2299 return (x < 0) ? gnm_fake_floor (x) : gnm_fake_ceil (x);
2300 }
2301
2302 static GnmValue *
gnumeric_roundup(GnmFuncEvalInfo * ei,GnmValue const * const * argv)2303 gnumeric_roundup (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
2304 {
2305 gnm_float number = value_get_as_float (argv[0]);
2306 gnm_float digits = argv[1] ? value_get_as_float (argv[1]) : 0;
2307
2308 if (digits >= 0) {
2309 if (digits <= GNM_MAX_EXP) {
2310 gnm_float p10 = gnm_pow10 ((int)digits);
2311 number = gnm_fake_roundup (number * p10) / p10;
2312 }
2313 } else {
2314 if (digits >= GNM_MIN_EXP) {
2315 /* Keep p10 integer. */
2316 gnm_float p10 = gnm_pow10 ((int)-digits);
2317 number = gnm_fake_roundup (number / p10) * p10;
2318 } else
2319 number = 0;
2320 }
2321
2322 return value_new_float (number);
2323 }
2324
2325 /***************************************************************************/
2326
2327 static GnmFuncHelp const help_mround[] = {
2328 { GNM_FUNC_HELP_NAME, F_("MROUND:@{x} rounded to a multiple of @{m}")},
2329 { GNM_FUNC_HELP_ARG, F_("x:number")},
2330 { GNM_FUNC_HELP_ARG, F_("m:number")},
2331 { GNM_FUNC_HELP_NOTE, F_("If @{x} and @{m} have different sign, MROUND returns #NUM!") },
2332 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
2333 { GNM_FUNC_HELP_EXAMPLES, "=MROUND(1.7,0.2)"},
2334 { GNM_FUNC_HELP_EXAMPLES, "=MROUND(321.123,0.12)"},
2335 { GNM_FUNC_HELP_SEEALSO, "ROUNDDOWN,ROUND,ROUNDUP"},
2336 { GNM_FUNC_HELP_END}
2337 };
2338
2339 static GnmValue *
gnumeric_mround(GnmFuncEvalInfo * ei,GnmValue const * const * argv)2340 gnumeric_mround (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
2341 {
2342 gnm_float const accuracy_limit = 0.0000003;
2343 gnm_float number, multiple;
2344 gnm_float div, mod;
2345 int sign = 1;
2346
2347 number = value_get_as_float (argv[0]);
2348 multiple = value_get_as_float (argv[1]);
2349
2350 /* Weird, but XL compatible. */
2351 if (multiple == 0)
2352 return value_new_int (0);
2353
2354 if ((number > 0 && multiple < 0)
2355 || (number < 0 && multiple > 0))
2356 return value_new_error_NUM (ei->pos);
2357
2358 if (number < 0) {
2359 sign = -1;
2360 number = -number;
2361 multiple = -multiple;
2362 }
2363
2364 mod = gnm_fmod (number, multiple);
2365 div = number - mod;
2366
2367 return value_new_float (sign * (
2368 div + ((mod + accuracy_limit >= multiple / 2) ? multiple : 0)));
2369 }
2370
2371 /***************************************************************************/
2372
2373 static GnmFuncHelp const help_arabic[] = {
2374 { GNM_FUNC_HELP_NAME, F_("ARABIC:the Roman numeral @{roman} as number")},
2375 { GNM_FUNC_HELP_ARG, F_("roman:Roman numeral")},
2376 { GNM_FUNC_HELP_DESCRIPTION, F_("Any Roman symbol to the left of a larger symbol "
2377 "(directly or indirectly) reduces the final value "
2378 "by the symbol amount, otherwise, it increases the "
2379 "final amount by the symbol's amount.") },
2380 { GNM_FUNC_HELP_ODF, F_("This function is OpenFormula compatible.")},
2381 { GNM_FUNC_HELP_EXAMPLES, "=ARABIC(\"I\")"},
2382 { GNM_FUNC_HELP_EXAMPLES, "=ARABIC(\"CDLII\")"},
2383 { GNM_FUNC_HELP_EXAMPLES, "=ARABIC(\"MCDXC\")"},
2384 { GNM_FUNC_HELP_EXAMPLES, "=ARABIC(\"MDCCCXCIX\")"},
2385 { GNM_FUNC_HELP_EXAMPLES, "=ARABIC(\"MCMXCIX\")"},
2386 { GNM_FUNC_HELP_EXAMPLES, "=ARABIC(\"mmmcmxcix\")"},
2387 { GNM_FUNC_HELP_EXAMPLES, "=ARABIC(\"MIM\")"},
2388 { GNM_FUNC_HELP_EXAMPLES, "=ARABIC(\"IVM\")"},
2389 { GNM_FUNC_HELP_SEEALSO, "ROMAN"},
2390 { GNM_FUNC_HELP_END}
2391 };
2392
2393 static GnmValue *
gnumeric_arabic(GnmFuncEvalInfo * ei,GnmValue const * const * argv)2394 gnumeric_arabic (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
2395 {
2396 const gchar *roman = (const gchar *)value_peek_string (argv[0]);
2397 int slen = strlen (roman);
2398 int last = 0;
2399 int result = 0;
2400 gchar *this = (gchar *)(roman + slen);
2401
2402 while (this > roman) {
2403 int this_val = 0;
2404 this = g_utf8_prev_char (this);
2405 switch (*this) {
2406 case 'i':
2407 case 'I':
2408 this_val = 1;
2409 break;
2410 case 'v':
2411 case 'V':
2412 this_val = 5;
2413 break;
2414 case 'x':
2415 case 'X':
2416 this_val = 10;
2417 break;
2418 case 'l':
2419 case 'L':
2420 this_val = 50;
2421 break;
2422 case 'c':
2423 case 'C':
2424 this_val = 100;
2425 break;
2426 case 'd':
2427 case 'D':
2428 this_val = 500;
2429 break;
2430 case 'm':
2431 case 'M':
2432 this_val = 1000;
2433 break;
2434 default:
2435 break;
2436 }
2437 if (this_val > 0) {
2438 if (this_val < last)
2439 result -= this_val;
2440 else {
2441 result += this_val;
2442 last = this_val;
2443 }
2444 }
2445 }
2446 return value_new_int (result);
2447 }
2448
2449 /***************************************************************************/
2450
2451 static GnmFuncHelp const help_roman[] = {
2452 { GNM_FUNC_HELP_NAME, F_("ROMAN:@{n} as a roman numeral text")},
2453 { GNM_FUNC_HELP_ARG, F_("n:non-negative integer")},
2454 { GNM_FUNC_HELP_ARG, F_("type:0,1,2,3,or 4, defaults to 0")},
2455 { GNM_FUNC_HELP_DESCRIPTION, F_("ROMAN returns the arabic number @{n} as a roman numeral text.\n"
2456 "If @{type} is 0 or it is omitted, ROMAN returns classic roman numbers.\n"
2457 "Type 1 is more concise than classic type, type 2 is more concise than "
2458 "type 1, and type 3 is more concise than type 2. Type 4 is a simplified type.")},
2459 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
2460 { GNM_FUNC_HELP_EXAMPLES, "=ROMAN(999)"},
2461 { GNM_FUNC_HELP_EXAMPLES, "=ROMAN(999,1)"},
2462 { GNM_FUNC_HELP_EXAMPLES, "=ROMAN(999,2)"},
2463 { GNM_FUNC_HELP_EXAMPLES, "=ROMAN(999,3)"},
2464 { GNM_FUNC_HELP_EXAMPLES, "=ROMAN(999,4)"},
2465 { GNM_FUNC_HELP_END}
2466 };
2467
2468 static GnmValue *
gnumeric_roman(GnmFuncEvalInfo * ei,GnmValue const * const * argv)2469 gnumeric_roman (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
2470 {
2471 static char const letter[] = { 'M', 'D', 'C', 'L', 'X', 'V', 'I' };
2472 int const largest = 1000;
2473 char buf[256];
2474 char *p;
2475 gnm_float n = gnm_floor (value_get_as_float (argv[0]));
2476 gnm_float form = argv[1] ? gnm_floor (value_get_as_float (argv[1])) : 0;
2477 int i, j, dec;
2478
2479 dec = largest;
2480
2481 if (n < 0 || n > 3999)
2482 return value_new_error_VALUE (ei->pos);
2483 if (form < 0 || form > 4)
2484 return value_new_error_VALUE (ei->pos);
2485
2486 if (n == 0)
2487 return value_new_string ("");
2488
2489 for (i = j = 0; dec > 1; dec /= 10, j += 2) {
2490 for (; n > 0; i++) {
2491 if (n >= dec) {
2492 buf[i] = letter[j];
2493 n -= dec;
2494 } else if (n >= dec - dec / 10) {
2495 buf[i++] = letter[j + 2];
2496 buf[i] = letter[j];
2497 n -= dec - dec / 10;
2498 } else if (n >= dec / 2) {
2499 buf[i] = letter[j + 1];
2500 n -= dec / 2;
2501 } else if (n >= dec / 2 - dec / 10) {
2502 buf[i++] = letter[j + 2];
2503 buf[i] = letter[j + 1];
2504 n -= dec / 2 - dec / 10;
2505 } else if (dec == 10) {
2506 buf[i] = letter[j + 2];
2507 n--;
2508 } else
2509 break;
2510 }
2511 }
2512 buf[i] = '\0';
2513
2514
2515 if (form > 0) {
2516 /* Replace ``XLV'' with ``VL'' */
2517 if ((p = strstr (buf, "XLV")) != NULL) {
2518 *p++ = 'V';
2519 *p++ = 'L';
2520 for ( ; *p; p++)
2521 *p = *(p+1);
2522 }
2523 /* Replace ``XCV'' with ``VC'' */
2524 if ((p = strstr (buf, "XCV")) != NULL) {
2525 *p++ = 'V';
2526 *p++ = 'C';
2527 for ( ; *p; p++)
2528 *p = *(p+1);
2529 }
2530 /* Replace ``CDL'' with ``LD'' */
2531 if ((p = strstr (buf, "CDL")) != NULL) {
2532 *p++ = 'L';
2533 *p++ = 'D';
2534 for ( ; *p; p++)
2535 *p = *(p+1);
2536 }
2537 /* Replace ``CML'' with ``LM'' */
2538 if ((p = strstr (buf, "CML")) != NULL) {
2539 *p++ = 'L';
2540 *p++ = 'M';
2541 for ( ; *p; p++)
2542 *p = *(p+1);
2543 }
2544 /* Replace ``CMVC'' with ``LMVL'' */
2545 if ((p = strstr (buf, "CMVC")) != NULL) {
2546 *p++ = 'L';
2547 *p++ = 'M';
2548 *p++ = 'V';
2549 *p++ = 'L';
2550 }
2551 }
2552 if (form == 1) {
2553 /* Replace ``CDXC'' with ``LDXL'' */
2554 if ((p = strstr (buf, "CDXC")) != NULL) {
2555 *p++ = 'L';
2556 *p++ = 'D';
2557 *p++ = 'X';
2558 *p++ = 'L';
2559 }
2560 /* Replace ``CDVC'' with ``LDVL'' */
2561 if ((p = strstr (buf, "CDVC")) != NULL) {
2562 *p++ = 'L';
2563 *p++ = 'D';
2564 *p++ = 'V';
2565 *p++ = 'L';
2566 }
2567 /* Replace ``CMXC'' with ``LMXL'' */
2568 if ((p = strstr (buf, "CMXC")) != NULL) {
2569 *p++ = 'L';
2570 *p++ = 'M';
2571 *p++ = 'X';
2572 *p++ = 'L';
2573 }
2574 /* Replace ``XCIX'' with ``VCIV'' */
2575 if ((p = strstr (buf, "XCIX")) != NULL) {
2576 *p++ = 'V';
2577 *p++ = 'C';
2578 *p++ = 'I';
2579 *p++ = 'V';
2580 }
2581 /* Replace ``XLIX'' with ``VLIV'' */
2582 if ((p = strstr (buf, "XLIX")) != NULL) {
2583 *p++ = 'V';
2584 *p++ = 'L';
2585 *p++ = 'I';
2586 *p++ = 'V';
2587 }
2588 }
2589 if (form > 1) {
2590 /* Replace ``XLIX'' with ``IL'' */
2591 if ((p = strstr (buf, "XLIX")) != NULL) {
2592 *p++ = 'I';
2593 *p++ = 'L';
2594 for ( ; *p; p++)
2595 *p = *(p+2);
2596 }
2597 /* Replace ``XCIX'' with ``IC'' */
2598 if ((p = strstr (buf, "XCIX")) != NULL) {
2599 *p++ = 'I';
2600 *p++ = 'C';
2601 for ( ; *p; p++)
2602 *p = *(p+2);
2603 }
2604 /* Replace ``CDXC'' with ``XD'' */
2605 if ((p = strstr (buf, "CDXC")) != NULL) {
2606 *p++ = 'X';
2607 *p++ = 'D';
2608 for ( ; *p; p++)
2609 *p = *(p+2);
2610 }
2611 /* Replace ``CDVC'' with ``XDV'' */
2612 if ((p = strstr (buf, "CDVC")) != NULL) {
2613 *p++ = 'X';
2614 *p++ = 'D';
2615 *p++ = 'V';
2616 for ( ; *p; p++)
2617 *p = *(p+1);
2618 }
2619 /* Replace ``CDIC'' with ``XDIX'' */
2620 if ((p = strstr (buf, "CDIC")) != NULL) {
2621 *p++ = 'X';
2622 *p++ = 'D';
2623 *p++ = 'I';
2624 *p++ = 'X';
2625 }
2626 /* Replace ``LMVL'' with ``XMV'' */
2627 if ((p = strstr (buf, "LMVL")) != NULL) {
2628 *p++ = 'X';
2629 *p++ = 'M';
2630 *p++ = 'V';
2631 for ( ; *p; p++)
2632 *p = *(p+1);
2633 }
2634 /* Replace ``CMIC'' with ``XMIX'' */
2635 if ((p = strstr (buf, "CMIC")) != NULL) {
2636 *p++ = 'X';
2637 *p++ = 'M';
2638 *p++ = 'I';
2639 *p++ = 'X';
2640 }
2641 /* Replace ``CMXC'' with ``XM'' */
2642 if ((p = strstr (buf, "CMXC")) != NULL) {
2643 *p++ = 'X';
2644 *p++ = 'M';
2645 for ( ; *p; p++)
2646 *p = *(p+2);
2647 }
2648 }
2649 if (form > 2) {
2650 /* Replace ``XDV'' with ``VD'' */
2651 if ((p = strstr (buf, "XDV")) != NULL) {
2652 *p++ = 'V';
2653 *p++ = 'D';
2654 for ( ; *p; p++)
2655 *p = *(p+1);
2656 }
2657 /* Replace ``XDIX'' with ``VDIV'' */
2658 if ((p = strstr (buf, "XDIX")) != NULL) {
2659 *p++ = 'V';
2660 *p++ = 'D';
2661 *p++ = 'I';
2662 *p++ = 'V';
2663 }
2664 /* Replace ``XMV'' with ``VM'' */
2665 if ((p = strstr (buf, "XMV")) != NULL) {
2666 *p++ = 'V';
2667 *p++ = 'M';
2668 for ( ; *p; p++)
2669 *p = *(p+1);
2670 }
2671 /* Replace ``XMIX'' with ``VMIV'' */
2672 if ((p = strstr (buf, "XMIX")) != NULL) {
2673 *p++ = 'V';
2674 *p++ = 'M';
2675 *p++ = 'I';
2676 *p++ = 'V';
2677 }
2678 }
2679 if (form == 4) {
2680 /* Replace ``VDIV'' with ``ID'' */
2681 if ((p = strstr (buf, "VDIV")) != NULL) {
2682 *p++ = 'I';
2683 *p++ = 'D';
2684 for ( ; *p; p++)
2685 *p = *(p+2);
2686 }
2687 /* Replace ``VMIV'' with ``IM'' */
2688 if ((p = strstr (buf, "VMIV")) != NULL) {
2689 *p++ = 'I';
2690 *p++ = 'M';
2691 for ( ; *p; p++)
2692 *p = *(p+2);
2693 }
2694 }
2695
2696 return value_new_string (buf);
2697 }
2698
2699 /***************************************************************************/
2700
2701 static GnmFuncHelp const help_sumx2my2[] = {
2702 { GNM_FUNC_HELP_NAME, F_("SUMX2MY2:sum of the difference of squares")},
2703 { GNM_FUNC_HELP_ARG, F_("array0:first cell area")},
2704 { GNM_FUNC_HELP_ARG, F_("array1:second cell area")},
2705 { GNM_FUNC_HELP_DESCRIPTION, F_("SUMX2MY2 function returns the sum of the difference of squares of "
2706 "corresponding values in two arrays. The equation of SUMX2MY2 is SUM(x^2-y^2).")},
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 SUMX2MY2(A1:A5,B1:B5) yields -1299.")},
2710 { GNM_FUNC_HELP_SEEALSO, "SUMSQ,SUMX2PY2"},
2711 { GNM_FUNC_HELP_END}
2712 };
2713
2714 static int
gnm_range_sumx2my2(gnm_float const * xs,const gnm_float * ys,int n,gnm_float * res)2715 gnm_range_sumx2my2 (gnm_float const *xs, const gnm_float *ys,
2716 int n, gnm_float *res)
2717 {
2718 gnm_float s = 0;
2719 int i;
2720
2721 for (i = 0; i < n; i++)
2722 s += xs[i] * xs[i] - ys[i] * ys[i];
2723
2724 *res = s;
2725 return 0;
2726 }
2727
2728
2729 static GnmValue *
gnumeric_sumx2my2(GnmFuncEvalInfo * ei,GnmValue const * const * argv)2730 gnumeric_sumx2my2 (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
2731 {
2732 return float_range_function2 (argv[0], argv[1],
2733 ei,
2734 gnm_range_sumx2my2,
2735 COLLECT_IGNORE_BLANKS |
2736 COLLECT_IGNORE_STRINGS |
2737 COLLECT_IGNORE_BOOLS,
2738 GNM_ERROR_VALUE);
2739 }
2740
2741 /***************************************************************************/
2742
2743 static GnmFuncHelp const help_sumx2py2[] = {
2744 { GNM_FUNC_HELP_NAME, F_("SUMX2PY2:sum of the sum of squares")},
2745 { GNM_FUNC_HELP_ARG, F_("array0:first cell area")},
2746 { GNM_FUNC_HELP_ARG, F_("array1:second cell area")},
2747 { GNM_FUNC_HELP_DESCRIPTION, F_("SUMX2PY2 function returns the sum of the sum of squares of "
2748 "corresponding values in two arrays. The equation of SUMX2PY2 is SUM(x^2+y^2).")},
2749 { GNM_FUNC_HELP_NOTE, F_("If @{array0} and @{array1} have different number of data points, SUMX2PY2 returns #N/A.\n"
2750 "Strings and empty cells are simply ignored.") },
2751 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
2752 { 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.") },
2753 { GNM_FUNC_HELP_EXAMPLES, F_("Then SUMX2PY2(A1:A5,B1:B5) yields 7149.") },
2754 { GNM_FUNC_HELP_SEEALSO, "SUMSQ,SUMX2MY2"},
2755 { GNM_FUNC_HELP_END}
2756 };
2757
2758 static int
gnm_range_sumx2py2(gnm_float const * xs,const gnm_float * ys,int n,gnm_float * res)2759 gnm_range_sumx2py2 (gnm_float const *xs, const gnm_float *ys,
2760 int n, gnm_float *res)
2761 {
2762 gnm_float s = 0;
2763 int i;
2764
2765 for (i = 0; i < n; i++)
2766 s += xs[i] * xs[i] + ys[i] * ys[i];
2767
2768 *res = s;
2769 return 0;
2770 }
2771
2772 static GnmValue *
gnumeric_sumx2py2(GnmFuncEvalInfo * ei,GnmValue const * const * argv)2773 gnumeric_sumx2py2 (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
2774 {
2775 return float_range_function2 (argv[0], argv[1],
2776 ei,
2777 gnm_range_sumx2py2,
2778 COLLECT_IGNORE_BLANKS |
2779 COLLECT_IGNORE_STRINGS |
2780 COLLECT_IGNORE_BOOLS,
2781 GNM_ERROR_VALUE);
2782 }
2783
2784 /***************************************************************************/
2785
2786 static GnmFuncHelp const help_sumxmy2[] = {
2787 { GNM_FUNC_HELP_NAME, F_("SUMXMY2:sum of the squares of differences")},
2788 { GNM_FUNC_HELP_ARG, F_("array0:first cell area")},
2789 { GNM_FUNC_HELP_ARG, F_("array1:second cell area")},
2790 { GNM_FUNC_HELP_DESCRIPTION, F_("SUMXMY2 function returns the sum of the squares of the differences of "
2791 "corresponding values in two arrays. The equation of SUMXMY2 is SUM((x-y)^2).")},
2792 { GNM_FUNC_HELP_NOTE, F_("If @{array0} and @{array1} have different number of data points, SUMXMY2 returns #N/A.\n"
2793 "Strings and empty cells are simply ignored.") },
2794 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
2795 { 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.") },
2796 { GNM_FUNC_HELP_EXAMPLES, F_("Then SUMXMY2(A1:A5,B1:B5) yields 409.") },
2797 { GNM_FUNC_HELP_SEEALSO, "SUMSQ,SUMX2MY2,SUMX2PY2"},
2798 { GNM_FUNC_HELP_END}
2799 };
2800
2801 static int
gnm_range_sumxmy2(gnm_float const * xs,const gnm_float * ys,int n,gnm_float * res)2802 gnm_range_sumxmy2 (gnm_float const *xs, const gnm_float *ys,
2803 int n, gnm_float *res)
2804 {
2805 gnm_float s = 0;
2806 int i;
2807
2808 for (i = 0; i < n; i++) {
2809 gnm_float d = (xs[i] - ys[i]);
2810 s += d * d;
2811 }
2812
2813 *res = s;
2814 return 0;
2815 }
2816
2817 static GnmValue *
gnumeric_sumxmy2(GnmFuncEvalInfo * ei,GnmValue const * const * argv)2818 gnumeric_sumxmy2 (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
2819 {
2820 return float_range_function2 (argv[0], argv[1],
2821 ei,
2822 gnm_range_sumxmy2,
2823 COLLECT_IGNORE_BLANKS |
2824 COLLECT_IGNORE_STRINGS |
2825 COLLECT_IGNORE_BOOLS,
2826 GNM_ERROR_VALUE);
2827 }
2828
2829 /***************************************************************************/
2830
2831 static GnmFuncHelp const help_seriessum[] = {
2832 { GNM_FUNC_HELP_NAME, F_("SERIESSUM:sum of a power series at @{x}")},
2833 { GNM_FUNC_HELP_ARG, F_("x:number where to evaluate the power series")},
2834 { GNM_FUNC_HELP_ARG, F_("n:non-negative integer, exponent of the lowest term of the series")},
2835 { GNM_FUNC_HELP_ARG, F_("m:increment to each exponent")},
2836 { GNM_FUNC_HELP_ARG, F_("coeff:coefficients of the power series")},
2837 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
2838 { 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.") },
2839 { GNM_FUNC_HELP_EXAMPLES, F_("Then SERIESSUM(2,1,2.23,A1:A5) evaluates as 5056.37439843926") },
2840 { GNM_FUNC_HELP_SEEALSO, "COUNT,SUM"},
2841 { GNM_FUNC_HELP_END}
2842 };
2843
2844 static GnmValue *
gnumeric_seriessum(GnmFuncEvalInfo * ei,GnmValue const * const * argv)2845 gnumeric_seriessum (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
2846 {
2847 gnm_float x = value_get_as_float (argv[0]);
2848 gnm_float n = value_get_as_float (argv[1]);
2849 gnm_float m = value_get_as_float (argv[2]);
2850 GnmValue *result = NULL;
2851 int N;
2852 /* Ignore blanks; err on bools or strings. */
2853 gnm_float *data =
2854 collect_floats_value (argv[3], ei->pos,
2855 COLLECT_IGNORE_BLANKS, &N, &result);
2856
2857 if (result)
2858 goto done;
2859
2860 if (x == 0) {
2861 if (n <= 0 || n + (N - 1) * m <= 0)
2862 result = value_new_error_NUM (ei->pos);
2863 else
2864 result = value_new_float (0);
2865 } else {
2866 gnm_float x_m = gnm_pow (x, m);
2867 gnm_float sum = 0;
2868 int i;
2869 x = gnm_pow (x, n);
2870
2871 for (i = 0; i < N; i++) {
2872 sum += data[i] * x;
2873 x *= x_m;
2874 }
2875
2876 if (gnm_finite (sum))
2877 result = value_new_float (sum);
2878 else
2879 result = value_new_error_NUM (ei->pos);
2880 }
2881
2882 done:
2883 g_free (data);
2884 return result;
2885 }
2886
2887 /***************************************************************************/
2888
2889 static GnmFuncHelp const help_minverse[] = {
2890 { GNM_FUNC_HELP_NAME, F_("MINVERSE:the inverse matrix of @{matrix}")},
2891 { GNM_FUNC_HELP_ARG, F_("matrix:a square matrix")},
2892 { GNM_FUNC_HELP_NOTE, F_("If @{matrix} is not invertible, MINVERSE returns #NUM!") },
2893 { GNM_FUNC_HELP_NOTE, F_("If @{matrix} does not contain an equal number of columns and rows, MINVERSE returns #VALUE!") },
2894 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
2895 { GNM_FUNC_HELP_SEEALSO, "MMULT,MDETERM,LINSOLVE"},
2896 { GNM_FUNC_HELP_END}
2897 };
2898
2899
2900 static GnmValue *
gnumeric_minverse(GnmFuncEvalInfo * ei,GnmValue const * const * argv)2901 gnumeric_minverse (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
2902 {
2903 GnmMatrix *A = NULL;
2904 GnmValue *res = NULL;
2905
2906 A = gnm_matrix_from_value (argv[0], &res, ei->pos);
2907 if (!A) goto out;
2908
2909 if (A->cols != A->rows || gnm_matrix_is_empty (A)) {
2910 res = value_new_error_VALUE (ei->pos);
2911 goto out;
2912 }
2913
2914 if (gnm_matrix_invert (A->data, A->rows))
2915 res = gnm_matrix_to_value (A);
2916 else
2917 res = value_new_error_NUM (ei->pos);
2918
2919 out:
2920 if (A) gnm_matrix_unref (A);
2921 return res;
2922 }
2923
2924 /***************************************************************************/
2925
2926 static GnmFuncHelp const help_mpseudoinverse[] = {
2927 { GNM_FUNC_HELP_NAME, F_("MPSEUDOINVERSE:the pseudo-inverse matrix of @{matrix}")},
2928 { GNM_FUNC_HELP_ARG, F_("matrix:a matrix")},
2929 { GNM_FUNC_HELP_ARG, F_("threshold:a relative size threshold for discarding eigenvalues")},
2930 { GNM_FUNC_HELP_SEEALSO, "MINVERSE"},
2931 { GNM_FUNC_HELP_END}
2932 };
2933
2934
2935 static GnmValue *
gnumeric_mpseudoinverse(GnmFuncEvalInfo * ei,GnmValue const * const * argv)2936 gnumeric_mpseudoinverse (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
2937 {
2938 GnmMatrix *A = NULL;
2939 GnmMatrix *B = NULL;
2940 GnmValue *res = NULL;
2941 gnm_float threshold = argv[1] ? value_get_as_float (argv[1]) : 256 * GNM_EPSILON;
2942
2943 A = gnm_matrix_from_value (argv[0], &res, ei->pos);
2944 if (!A) goto out;
2945
2946 if (gnm_matrix_is_empty (A)) {
2947 res = value_new_error_VALUE (ei->pos);
2948 goto out;
2949 }
2950
2951 B = gnm_matrix_new (A->cols, A->rows); /* Shape of A^t */
2952 gnm_matrix_pseudo_inverse (A->data, A->rows, A->cols, threshold, B->data);
2953 res = gnm_matrix_to_value (B);
2954
2955 out:
2956 if (A) gnm_matrix_unref (A);
2957 if (B) gnm_matrix_unref (B);
2958 return res;
2959 }
2960
2961 /***************************************************************************/
2962
2963 static GnmFuncHelp const help_cholesky[] = {
2964 { GNM_FUNC_HELP_NAME, F_("CHOLESKY:the Cholesky decomposition of the symmetric positive-definite @{matrix}")},
2965 { GNM_FUNC_HELP_ARG, F_("matrix:a symmetric positive definite matrix")},
2966 { GNM_FUNC_HELP_NOTE, F_("If the Cholesky-Banachiewicz algorithm applied to @{matrix} fails, Cholesky returns #NUM!") },
2967 { GNM_FUNC_HELP_NOTE, F_("If @{matrix} does not contain an equal number of columns and rows, CHOLESKY returns #VALUE!") },
2968 { GNM_FUNC_HELP_SEEALSO, "MINVERSE,MMULT,MDETERM"},
2969 { GNM_FUNC_HELP_END}
2970 };
2971
2972 static gboolean
gnm_matrix_cholesky(GnmMatrix const * A,GnmMatrix * B)2973 gnm_matrix_cholesky (GnmMatrix const *A, GnmMatrix *B)
2974 {
2975 int r, c, k;
2976 gnm_float sum;
2977 int n = A->cols;
2978
2979 for (r = 0; r < n; r++) {
2980 for (c = 0; c < r; c++) {
2981 sum = 0.;
2982 for (k = 0; k < c; k++)
2983 sum += B->data[r][k] * B->data[c][k];
2984 B->data[c][r] = 0;
2985 B->data[r][c] = (A->data[r][c] - sum) / B->data[c][c];
2986 }
2987 sum = 0;
2988 for (k = 0; k < r; k++)
2989 sum += B->data[r][k] * B->data[r][k];
2990 B->data[r][r] = gnm_sqrt (A->data[r][r] - sum);
2991 }
2992 return TRUE;
2993 }
2994
2995 static void
make_symmetric(GnmMatrix * m)2996 make_symmetric (GnmMatrix *m)
2997 {
2998 int c, r;
2999
3000 g_return_if_fail (m->cols == m->rows);
3001
3002 for (c = 0; c < m->cols; ++c) {
3003 for (r = c + 1; r < m->rows; ++r) {
3004 gnm_float a = (m->data[r][c] + m->data[c][r]) / 2;
3005 m->data[r][c] = m->data[c][r] = a;
3006 }
3007 }
3008 }
3009
3010 static GnmValue *
gnumeric_cholesky(GnmFuncEvalInfo * ei,GnmValue const * const * argv)3011 gnumeric_cholesky (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
3012 {
3013 GnmMatrix *A = NULL;
3014 GnmMatrix *B = NULL;
3015 GnmValue *res = NULL;
3016
3017 A = gnm_matrix_from_value (argv[0], &res, ei->pos);
3018 if (!A) goto out;
3019
3020 if (A->cols != A->rows || gnm_matrix_is_empty (A)) {
3021 res = value_new_error_VALUE (ei->pos);
3022 goto out;
3023 }
3024 make_symmetric (A);
3025
3026 B = gnm_matrix_new (A->rows, A->cols);
3027
3028 if (gnm_matrix_cholesky (A, B))
3029 res = gnm_matrix_to_value (B);
3030 else
3031 res = value_new_error_NUM (ei->pos);
3032
3033 out:
3034 if (A) gnm_matrix_unref (A);
3035 if (B) gnm_matrix_unref (B);
3036 return res;
3037 }
3038
3039 /***************************************************************************/
3040
3041 static GnmFuncHelp const help_munit[] = {
3042 { GNM_FUNC_HELP_NAME, F_("MUNIT:the @{n} by @{n} identity matrix")},
3043 { GNM_FUNC_HELP_ARG, F_("n:size of the matrix")},
3044 { GNM_FUNC_HELP_ODF, F_("This function is OpenFormula compatible.")},
3045 { GNM_FUNC_HELP_SEEALSO, "MMULT,MDETERM,MINVERSE"},
3046 { GNM_FUNC_HELP_END}
3047 };
3048
3049 static GnmValue *
gnumeric_munit(GnmFuncEvalInfo * ei,GnmValue const * const * argv)3050 gnumeric_munit (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
3051 {
3052 gnm_float n = value_get_as_float (argv[0]);
3053 gint c, ni;
3054 GnmValue *res;
3055
3056 if (n < 1)
3057 return value_new_error_NUM (ei->pos);
3058
3059 /*
3060 * This provides some protection against bogus sizes and
3061 * running out of memory.
3062 */
3063 if (n * n >= G_MAXINT ||
3064 n > 5000) /* Arbitrary */
3065 return value_new_error_NUM (ei->pos);
3066
3067 ni = (int)n;
3068 res = value_new_array (ni, ni);
3069 for (c = 0; c < ni; ++c) {
3070 value_release (res->v_array.vals[c][c]);
3071 res->v_array.vals[c][c] = value_new_int (1);
3072 }
3073
3074 return res;
3075 }
3076
3077 /***************************************************************************/
3078
3079 static GnmFuncHelp const help_mmult[] = {
3080 { GNM_FUNC_HELP_NAME, F_("MMULT:the matrix product of @{mat1} and @{mat2}")},
3081 { GNM_FUNC_HELP_ARG, F_("mat1:a matrix")},
3082 { GNM_FUNC_HELP_ARG, F_("mat2:a matrix")},
3083 { 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}).") },
3084 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
3085 { GNM_FUNC_HELP_SEEALSO, "TRANSPOSE,MINVERSE"},
3086 { GNM_FUNC_HELP_END}
3087 };
3088
3089
3090 static GnmValue *
gnumeric_mmult(GnmFuncEvalInfo * ei,GnmValue const * const * argv)3091 gnumeric_mmult (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
3092 {
3093 GnmMatrix *A = NULL;
3094 GnmMatrix *B = NULL;
3095 GnmMatrix *C = NULL;
3096 GnmValue *res = NULL;
3097
3098 A = gnm_matrix_from_value (argv[0], &res, ei->pos);
3099 if (!A) goto out;
3100
3101 B = gnm_matrix_from_value (argv[1], &res, ei->pos);
3102 if (!B) goto out;
3103
3104 if (A->cols != B->rows || gnm_matrix_is_empty (A) || gnm_matrix_is_empty (B)) {
3105 res = value_new_error_VALUE (ei->pos);
3106 goto out;
3107 }
3108
3109 C = gnm_matrix_new (A->rows, B->cols);
3110 gnm_matrix_multiply (C, A, B);
3111 res = gnm_matrix_to_value (C);
3112
3113 out:
3114 if (A) gnm_matrix_unref (A);
3115 if (B) gnm_matrix_unref (B);
3116 if (C) gnm_matrix_unref (C);
3117 return res;
3118 }
3119
3120 /***************************************************************************/
3121
3122 static GnmFuncHelp const help_linsolve[] = {
3123 { GNM_FUNC_HELP_NAME, F_("LINSOLVE:solve linear equation")},
3124 { GNM_FUNC_HELP_ARG, F_("A:a matrix")},
3125 { GNM_FUNC_HELP_ARG, F_("B:a matrix")},
3126 { GNM_FUNC_HELP_DESCRIPTION,
3127 F_("Solves the equation @{A}*X=@{B} and returns X.") },
3128 { GNM_FUNC_HELP_NOTE, F_("If the matrix @{A} is singular, #VALUE! is returned.") },
3129 { GNM_FUNC_HELP_SEEALSO, "MINVERSE"},
3130 { GNM_FUNC_HELP_END}
3131 };
3132
3133
3134 static GnmValue *
gnumeric_linsolve(GnmFuncEvalInfo * ei,GnmValue const * const * argv)3135 gnumeric_linsolve (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
3136 {
3137 GnmMatrix *A = NULL;
3138 GnmMatrix *B = NULL;
3139 GnmValue *res = NULL;
3140 GORegressionResult regres;
3141
3142 A = gnm_matrix_from_value (argv[0], &res, ei->pos);
3143 if (!A) goto out;
3144
3145 B = gnm_matrix_from_value (argv[1], &res, ei->pos);
3146 if (!B) goto out;
3147
3148 if (A->cols != A->rows || gnm_matrix_is_empty (A) ||
3149 B->rows != A->rows || gnm_matrix_is_empty (B)) {
3150 res = value_new_error_VALUE (ei->pos);
3151 goto out;
3152 }
3153
3154 regres = gnm_linear_solve_multiple (A, B);
3155
3156 if (regres != GO_REG_ok && regres != GO_REG_near_singular_good) {
3157 res = value_new_error_NUM (ei->pos);
3158 } else {
3159 int c, r;
3160
3161 res = value_new_array_non_init (B->cols, B->rows);
3162 for (c = 0; c < B->cols; c++) {
3163 res->v_array.vals[c] = g_new (GnmValue *, B->rows);
3164 for (r = 0; r < B->rows; r++)
3165 res->v_array.vals[c][r] =
3166 value_new_float (B->data[r][c]);
3167 }
3168 }
3169
3170 out:
3171 if (A) gnm_matrix_unref (A);
3172 if (B) gnm_matrix_unref (B);
3173 return res;
3174 }
3175
3176 /***************************************************************************/
3177
3178 static GnmFuncHelp const help_mdeterm[] = {
3179 { GNM_FUNC_HELP_NAME, F_("MDETERM:the determinant of the matrix @{matrix}")},
3180 { GNM_FUNC_HELP_ARG, F_("matrix:a square matrix")},
3181 { 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.")},
3182 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
3183 { GNM_FUNC_HELP_SEEALSO, "MMULT,MINVERSE"},
3184 { GNM_FUNC_HELP_END}
3185 };
3186
3187 static GnmValue *
gnumeric_mdeterm(GnmFuncEvalInfo * ei,GnmValue const * const * argv)3188 gnumeric_mdeterm (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
3189 {
3190 GnmMatrix *A = NULL;
3191 GnmValue *res = NULL;
3192
3193 A = gnm_matrix_from_value (argv[0], &res, ei->pos);
3194 if (!A) goto out;
3195
3196 if (A->cols != A->rows || gnm_matrix_is_empty (A)) {
3197 res = value_new_error_VALUE (ei->pos);
3198 goto out;
3199 }
3200
3201 res = value_new_float (gnm_matrix_determinant (A->data, A->rows));
3202
3203 out:
3204 if (A) gnm_matrix_unref (A);
3205 return res;
3206 }
3207
3208 /***************************************************************************/
3209
3210 static GnmFuncHelp const help_sumproduct[] = {
3211 { GNM_FUNC_HELP_NAME, F_("SUMPRODUCT:multiplies components and adds the results") },
3212 { GNM_FUNC_HELP_DESCRIPTION,
3213 F_("Multiplies corresponding data entries in the "
3214 "given arrays or ranges, and then returns the sum of those "
3215 "products.") },
3216 { GNM_FUNC_HELP_NOTE, F_("If an entry is not numeric, the value zero is used instead.") },
3217 { GNM_FUNC_HELP_NOTE, F_("If arrays or range arguments do not have the same dimensions, "
3218 "return #VALUE! error.") },
3219 { GNM_FUNC_HELP_NOTE, F_("This function ignores logicals, so using SUMPRODUCT(A1:A5>0) will not work. Instead use SUMPRODUCT(--(A1:A5>0))") },
3220 #if 0
3221 "@EXAMPLES=\n"
3222 "Let us assume that the cells A1, A2, ..., A5 contain numbers "
3223 "11, 15, 17, 21, and 43 and the cells B1, B2, ..., B5 hold "
3224 "numbers 13, 22, 31, 33, and 39. Then\n"
3225 "SUMPRODUCT(A1:A5,B1:B5) equals 3370.\n"
3226 #endif
3227 { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
3228 { GNM_FUNC_HELP_ODF, F_("This function is not OpenFormula compatible. Use ODF.SUMPRODUCT instead.") },
3229 { GNM_FUNC_HELP_SEEALSO, "SUM,PRODUCT,G_PRODUCT,ODF.SUMPRODUCT" },
3230 { GNM_FUNC_HELP_END }
3231 };
3232
3233 static GnmFuncHelp const help_odf_sumproduct[] = {
3234 { GNM_FUNC_HELP_NAME, F_("ODF.SUMPRODUCT:multiplies components and adds the results") },
3235 { GNM_FUNC_HELP_DESCRIPTION,
3236 F_("Multiplies corresponding data entries in the "
3237 "given arrays or ranges, and then returns the sum of those "
3238 "products.") },
3239 { GNM_FUNC_HELP_NOTE, F_("If an entry is not numeric or logical, the value zero is used instead.") },
3240 { GNM_FUNC_HELP_NOTE, F_("If arrays or range arguments do not have the same dimensions, "
3241 "return #VALUE! error.") },
3242 { GNM_FUNC_HELP_NOTE, F_("This function differs from SUMPRODUCT by considering booleans.") },
3243 { GNM_FUNC_HELP_EXCEL, F_("This function is not Excel compatible. Use SUMPRODUCT instead.") },
3244 { GNM_FUNC_HELP_ODF, F_("This function is OpenFormula compatible.") },
3245 { GNM_FUNC_HELP_SEEALSO, "SUMPRODUCT,SUM,PRODUCT,G_PRODUCT" },
3246 { GNM_FUNC_HELP_END }
3247 };
3248
3249 static GnmValue *
gnumeric_sumproduct_common(gboolean ignore_bools,GnmFuncEvalInfo * ei,int argc,GnmExprConstPtr const * argv)3250 gnumeric_sumproduct_common (gboolean ignore_bools, GnmFuncEvalInfo *ei,
3251 int argc, GnmExprConstPtr const *argv)
3252 {
3253 gnm_float **data;
3254 GnmValue *result;
3255 int i;
3256 gboolean size_error = FALSE;
3257 int sizex = -1, sizey = -1;
3258
3259 if (argc == 0)
3260 return value_new_error_VALUE (ei->pos);
3261
3262 data = g_new0 (gnm_float *, argc);
3263
3264 for (i = 0; i < argc; i++) {
3265 int thissizex, thissizey, x, y;
3266 GnmExpr const *expr = argv[i];
3267 GnmValue *val = gnm_expr_eval
3268 (expr, ei->pos,
3269 GNM_EXPR_EVAL_PERMIT_NON_SCALAR |
3270 GNM_EXPR_EVAL_PERMIT_EMPTY);
3271
3272 if (!val) {
3273 size_error = TRUE;
3274 break;
3275 }
3276
3277 thissizex = value_area_get_width (val, ei->pos);
3278 thissizey = value_area_get_height (val, ei->pos);
3279
3280 if (i == 0) {
3281 sizex = thissizex;
3282 sizey = thissizey;
3283 } else if (sizex != thissizex || sizey != thissizey)
3284 size_error = TRUE;
3285
3286 data[i] = g_new (gnm_float, thissizex * thissizey);
3287 for (y = 0; y < thissizey; y++) {
3288 for (x = 0; x < thissizex; x++) {
3289 /* FIXME: efficiency worries? */
3290 GnmValue const *v = value_area_fetch_x_y (val, x, y, ei->pos);
3291 switch (v->v_any.type) {
3292 case VALUE_ERROR:
3293 /*
3294 * We carefully tranverse the argument
3295 * list and then the arrays in such an
3296 * order that the first error we see is
3297 * the final result.
3298 *
3299 * args: left-to-right.
3300 * arrays: horizontal before vertical.
3301 *
3302 * Oh, size_error has the lowest
3303 * significance -- it will be checked
3304 * outside the arg loop.
3305 */
3306 result = value_dup (v);
3307 value_release (val);
3308 goto done;
3309 case VALUE_FLOAT:
3310 data[i][y * thissizex + x] = value_get_as_float (v);
3311 break;
3312 case VALUE_BOOLEAN:
3313 data[i][y * thissizex + x] =
3314 ignore_bools
3315 ? 0.0
3316 : value_get_as_float (v);
3317 break;
3318 default :
3319 /* Ignore strings to be consistent with XL */
3320 data[i][y * thissizex + x] = 0.;
3321 }
3322 }
3323 }
3324 value_release (val);
3325 }
3326
3327 if (size_error) {
3328 /*
3329 * If we found no errors in the data set and also the sizes
3330 * do not match, we will get here.
3331 */
3332 result = value_new_error_VALUE (ei->pos);
3333 } else {
3334
3335 void *state = gnm_accumulator_start ();
3336 GnmAccumulator *acc = gnm_accumulator_new ();
3337 int j;
3338
3339 for (j = 0; j < sizex * sizey; j++) {
3340 int i;
3341 GnmQuad product;
3342 gnm_quad_init (&product, data[0][j]);
3343 for (i = 1; i < argc; i++) {
3344 GnmQuad q;
3345 gnm_quad_init (&q, data[i][j]);
3346 gnm_quad_mul (&product, &product, &q);
3347 }
3348 gnm_accumulator_add_quad (acc, &product);
3349 }
3350
3351 result = value_new_float (gnm_accumulator_value (acc));
3352 gnm_accumulator_free (acc);
3353 gnm_accumulator_end (state);
3354 }
3355
3356 done:
3357 for (i = 0; i < argc; i++)
3358 g_free (data[i]);
3359 g_free (data);
3360 return result;
3361 }
3362
3363 static GnmValue *
gnumeric_sumproduct(GnmFuncEvalInfo * ei,int argc,GnmExprConstPtr const * argv)3364 gnumeric_sumproduct (GnmFuncEvalInfo *ei, int argc, GnmExprConstPtr const *argv)
3365 {
3366 return gnumeric_sumproduct_common (TRUE, ei, argc, argv);
3367 }
3368
3369 static GnmValue *
gnumeric_odf_sumproduct(GnmFuncEvalInfo * ei,int argc,GnmExprConstPtr const * argv)3370 gnumeric_odf_sumproduct (GnmFuncEvalInfo *ei, int argc, GnmExprConstPtr const *argv)
3371 {
3372 return gnumeric_sumproduct_common (FALSE, ei, argc, argv);
3373 }
3374
3375 /***************************************************************************/
3376
3377 static GnmFuncHelp const help_eigen[] = {
3378 { GNM_FUNC_HELP_NAME, F_("EIGEN:eigenvalues and eigenvectors of the symmetric @{matrix}")},
3379 { GNM_FUNC_HELP_ARG, F_("matrix:a symmetric matrix")},
3380 { 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.") },
3381 { GNM_FUNC_HELP_NOTE, F_("If @{matrix} does not contain an equal number of columns and rows, EIGEN returns #VALUE!") },
3382 // { GNM_FUNC_HELP_EXAMPLES, "=EIGEN({1,2;3,2})" },
3383 { GNM_FUNC_HELP_END}
3384 };
3385
3386
3387 typedef struct {
3388 gnm_float val;
3389 int index;
3390 } gnumeric_eigen_ev_t;
3391
3392 static int
compare_gnumeric_eigen_ev(const void * a,const void * b)3393 compare_gnumeric_eigen_ev (const void *a, const void *b)
3394 {
3395 const gnumeric_eigen_ev_t *da = a;
3396 const gnumeric_eigen_ev_t *db = b;
3397 gnm_float ea = da->val;
3398 gnm_float eb = db->val;
3399
3400 /* Compare first by magnitude (descending). */
3401 if (gnm_abs (ea) > gnm_abs (eb))
3402 return -1;
3403 else if (gnm_abs (ea) < gnm_abs (eb))
3404 return +1;
3405
3406 /* Then by value, i.e., sign, still descending. */
3407 if (ea > eb)
3408 return -1;
3409 else if (ea < eb)
3410 return +1;
3411 else
3412 return 0;
3413 }
3414
3415 static GnmValue *
gnumeric_eigen(GnmFuncEvalInfo * ei,GnmValue const * const * argv)3416 gnumeric_eigen (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
3417 {
3418 GnmMatrix *A = NULL;
3419 GnmMatrix *EIG = NULL;
3420 gnm_float *eigenvalues = NULL;
3421 GnmValue *res = NULL;
3422 int i, c, r;
3423 gnumeric_eigen_ev_t *ev_sort;
3424
3425 A = gnm_matrix_from_value (argv[0], &res, ei->pos);
3426 if (!A) goto out;
3427
3428 if (A->cols != A->rows || gnm_matrix_is_empty (A)) {
3429 res = value_new_error_VALUE (ei->pos);
3430 goto out;
3431 }
3432
3433 make_symmetric (A);
3434 EIG = gnm_matrix_new (A->rows, A->cols);
3435 eigenvalues = g_new0 (gnm_float, A->cols);
3436
3437 if (!gnm_matrix_eigen (A, EIG, eigenvalues)) {
3438 res = value_new_error_NUM (ei->pos);
3439 goto out;
3440 }
3441
3442 /* Sorting eigenvalues */
3443 ev_sort = g_new (gnumeric_eigen_ev_t, A->cols);
3444 for (i = 0; i < A->cols; i++) {
3445 ev_sort[i].val = eigenvalues[i];
3446 ev_sort[i].index = i;
3447 }
3448 qsort (ev_sort, A->cols, sizeof (gnumeric_eigen_ev_t), compare_gnumeric_eigen_ev);
3449
3450 res = value_new_array_non_init (A->cols, A->rows + 1);
3451 for (c = 0; c < A->cols; ++c) {
3452 res->v_array.vals[c] = g_new (GnmValue *, A->rows + 1);
3453 res->v_array.vals[c][0] = value_new_float (eigenvalues[ev_sort[c].index]);
3454 for (r = 0; r < A->rows; ++r) {
3455 gnm_float tmp = EIG->data[r][ev_sort[c].index];
3456 res->v_array.vals[c][r + 1] = value_new_float (tmp);
3457 }
3458 }
3459
3460 g_free (ev_sort);
3461
3462 out:
3463 if (A) gnm_matrix_unref (A);
3464 if (EIG) gnm_matrix_unref (EIG);
3465 g_free (eigenvalues);
3466 return res;
3467 }
3468
3469
3470 /***************************************************************************/
3471
3472 GnmFuncDescriptor const math_functions[] = {
3473 { "abs", "f", help_abs,
3474 gnumeric_abs, NULL,
3475 GNM_FUNC_SIMPLE + GNM_FUNC_AUTO_FIRST,
3476 GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3477 { "acos", "f", help_acos,
3478 gnumeric_acos, NULL,
3479 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3480 { "acosh", "f", help_acosh,
3481 gnumeric_acosh, NULL,
3482 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3483 { "acot", "f", help_acot,
3484 gnumeric_acot, NULL,
3485 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_NO_TESTSUITE },
3486 { "acoth", "f", help_acoth,
3487 gnumeric_acoth, NULL,
3488 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_NO_TESTSUITE },
3489 { "agm", "ff", help_agm,
3490 gnumeric_agm, NULL,
3491 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3492 { "arabic", "S", help_arabic,
3493 gnumeric_arabic, NULL,
3494 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_NO_TESTSUITE },
3495 { "asin", "f", help_asin,
3496 gnumeric_asin, NULL,
3497 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3498 { "asinh", "f", help_asinh,
3499 gnumeric_asinh, NULL,
3500 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3501 { "atan", "f", help_atan,
3502 gnumeric_atan, NULL,
3503 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3504 { "atanh", "f", help_atanh,
3505 gnumeric_atanh, NULL,
3506 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3507 { "atan2", "ff", help_atan2,
3508 gnumeric_atan2, NULL,
3509 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3510 { "beta", "ff", help_beta,
3511 gnumeric_beta, NULL,
3512 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3513 { "betaln", "ff", help_betaln,
3514 gnumeric_betaln, NULL,
3515 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC, GNM_FUNC_TEST_STATUS_NO_TESTSUITE },
3516 { "cholesky","A", help_cholesky,
3517 gnumeric_cholesky, NULL,
3518 GNM_FUNC_RETURNS_NON_SCALAR, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC, GNM_FUNC_TEST_STATUS_NO_TESTSUITE },
3519 { "cos", "f", help_cos,
3520 gnumeric_cos, NULL,
3521 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3522 { "cosh", "f", help_cosh,
3523 gnumeric_cosh, NULL,
3524 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3525 { "cospi", "f", help_cospi,
3526 gnumeric_cospi, NULL,
3527 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3528 { "cot", "f", help_cot,
3529 gnumeric_cot, NULL,
3530 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_NO_TESTSUITE },
3531 { "cotpi", "f", help_cotpi,
3532 gnumeric_cotpi, NULL,
3533 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_NO_TESTSUITE },
3534 { "coth", "f", help_coth,
3535 gnumeric_coth, NULL,
3536 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_NO_TESTSUITE },
3537
3538 { "countif", "rS", help_countif,
3539 gnumeric_countif, NULL,
3540 GNM_FUNC_SIMPLE + GNM_FUNC_AUTO_UNITLESS,
3541 GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3542 { "countifs", NULL, help_countifs,
3543 NULL, gnumeric_countifs,
3544 GNM_FUNC_SIMPLE + GNM_FUNC_AUTO_UNITLESS,
3545 GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3546
3547 { "ceil", "f", help_ceil,
3548 gnumeric_ceil, NULL,
3549 GNM_FUNC_SIMPLE + GNM_FUNC_AUTO_FIRST,
3550 GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC, GNM_FUNC_TEST_STATUS_NO_TESTSUITE },
3551 { "ceiling", "f|f", help_ceiling,
3552 gnumeric_ceiling, NULL,
3553 GNM_FUNC_SIMPLE + GNM_FUNC_AUTO_FIRST,
3554 GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3555 { "degrees", "f", help_degrees,
3556 gnumeric_degrees, NULL,
3557 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3558 { "even", "f", help_even,
3559 gnumeric_even, NULL,
3560 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3561 { "exp", "f", help_exp,
3562 gnumeric_exp, NULL,
3563 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3564 { "expm1", "f", help_expm1,
3565 gnumeric_expm1, NULL,
3566 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3567 { "fact", "f", help_fact,
3568 gnumeric_fact, NULL,
3569 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_SUPERSET, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3570
3571 /* MS Excel puts this in the engineering functions */
3572 { "factdouble", "f", help_factdouble,
3573 gnumeric_factdouble, NULL,
3574 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3575
3576 { "fib", "f", help_fib,
3577 gnumeric_fib, NULL,
3578 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3579 { "combin", "ff", help_combin,
3580 gnumeric_combin, NULL,
3581 GNM_FUNC_SIMPLE + GNM_FUNC_AUTO_UNITLESS,
3582 GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3583 { "combina", "ff", help_combina,
3584 gnumeric_combina, NULL,
3585 GNM_FUNC_SIMPLE + GNM_FUNC_AUTO_UNITLESS,
3586 GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_NO_TESTSUITE },
3587 { "csc", "f", help_csc,
3588 gnumeric_csc, NULL,
3589 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC, GNM_FUNC_TEST_STATUS_NO_TESTSUITE },
3590 { "csch", "f", help_csch,
3591 gnumeric_csch, NULL,
3592 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC, GNM_FUNC_TEST_STATUS_NO_TESTSUITE },
3593 { "floor", "f|f", help_floor,
3594 gnumeric_floor, NULL,
3595 GNM_FUNC_SIMPLE + GNM_FUNC_AUTO_FIRST,
3596 GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3597 { "digamma", "f", help_digamma,
3598 gnumeric_digamma, NULL,
3599 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC, GNM_FUNC_TEST_STATUS_BASIC },
3600 { "gamma", "f", help_gamma,
3601 gnumeric_gamma, NULL,
3602 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3603 { "gammaln", "f",
3604 help_gammaln, gnumeric_gammaln, NULL,
3605 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3606 { "gcd", NULL, help_gcd,
3607 NULL, gnumeric_gcd,
3608 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3609 { "gd", "f", help_gd,
3610 gnumeric_gd, NULL,
3611 GNM_FUNC_SIMPLE,
3612 GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3613 { "hypot", NULL, help_hypot,
3614 NULL, gnumeric_hypot,
3615 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC, GNM_FUNC_TEST_STATUS_NO_TESTSUITE },
3616 { "igamma", "ff|bbb", help_igamma,
3617 gnumeric_igamma, NULL,
3618 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC, GNM_FUNC_TEST_STATUS_NO_TESTSUITE },
3619 { "int", "f", help_int,
3620 gnumeric_int, NULL,
3621 GNM_FUNC_SIMPLE + GNM_FUNC_AUTO_FIRST,
3622 GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3623 { "lambertw", "f|f", help_lambertw,
3624 gnumeric_lambertw, NULL,
3625 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3626 { "lcm", NULL, help_lcm,
3627 NULL, gnumeric_lcm,
3628 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3629 { "ln", "f", help_ln,
3630 gnumeric_ln, NULL,
3631 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3632 { "ln1p", "f", help_ln1p,
3633 gnumeric_ln1p, NULL,
3634 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3635 { "log", "f|f", help_log,
3636 gnumeric_log, NULL,
3637 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3638 { "log2", "f", help_log2,
3639 gnumeric_log2, NULL,
3640 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3641 { "log10", "f", help_log10,
3642 gnumeric_log10, NULL,
3643 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3644 { "mod", "ff", help_mod,
3645 gnumeric_mod, NULL,
3646 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3647 { "mround", "ff", help_mround,
3648 gnumeric_mround, NULL,
3649 GNM_FUNC_SIMPLE + GNM_FUNC_AUTO_FIRST,
3650 GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3651 { "multinomial", NULL, help_multinomial,
3652 NULL, gnumeric_multinomial,
3653 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3654 { "odd" , "f", help_odd,
3655 gnumeric_odd, NULL,
3656 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3657 { "power", "ff|f", help_power,
3658 gnumeric_power, NULL,
3659 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_SUPERSET, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3660 { "pochhammer", "ff", help_pochhammer,
3661 gnumeric_pochhammer, NULL,
3662 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3663 { "g_product", NULL, help_g_product,
3664 NULL, gnumeric_g_product,
3665 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3666 { "quotient" , "ff", help_quotient,
3667 gnumeric_quotient, NULL,
3668 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3669 { "radians", "f", help_radians,
3670 gnumeric_radians, NULL,
3671 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3672 { "reducepi", "ff|f", help_reducepi,
3673 gnumeric_reducepi, NULL,
3674 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC, GNM_FUNC_TEST_STATUS_NO_TESTSUITE },
3675 { "roman", "f|f", help_roman,
3676 gnumeric_roman, NULL,
3677 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3678 { "round", "f|f", help_round,
3679 gnumeric_round, NULL,
3680 GNM_FUNC_SIMPLE + GNM_FUNC_AUTO_FIRST,
3681 GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3682 { "rounddown", "f|f", help_rounddown,
3683 gnumeric_rounddown, NULL,
3684 GNM_FUNC_SIMPLE + GNM_FUNC_AUTO_FIRST,
3685 GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3686 { "roundup", "f|f", help_roundup,
3687 gnumeric_roundup, NULL,
3688 GNM_FUNC_SIMPLE + GNM_FUNC_AUTO_FIRST,
3689 GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3690 { "sec", "f", help_sec,
3691 gnumeric_sec, NULL,
3692 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC, GNM_FUNC_TEST_STATUS_NO_TESTSUITE },
3693 { "sech", "f", help_sech,
3694 gnumeric_sech, NULL,
3695 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC, GNM_FUNC_TEST_STATUS_NO_TESTSUITE },
3696 { "seriessum", "fffA", help_seriessum,
3697 gnumeric_seriessum, NULL,
3698 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3699 { "sign", "f", help_sign,
3700 gnumeric_sign, NULL,
3701 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3702 { "sin", "f", help_sin,
3703 gnumeric_sin, NULL,
3704 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3705 { "sinh", "f", help_sinh,
3706 gnumeric_sinh, NULL,
3707 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3708 { "sinpi", "f", help_sinpi,
3709 gnumeric_sinpi, NULL,
3710 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3711 { "sqrt", "f", help_sqrt,
3712 gnumeric_sqrt, NULL,
3713 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3714 { "sqrtpi", "f", help_sqrtpi,
3715 gnumeric_sqrtpi, NULL,
3716 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3717 { "suma", NULL, help_suma,
3718 NULL, gnumeric_suma,
3719 GNM_FUNC_SIMPLE + GNM_FUNC_AUTO_FIRST,
3720 GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3721 { "sumif", "rS|r", help_sumif,
3722 gnumeric_sumif, NULL,
3723 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3724 { "sumifs", NULL, help_sumifs,
3725 NULL, gnumeric_sumifs,
3726 GNM_FUNC_SIMPLE,
3727 GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3728 { "averageif", "rS|r", help_averageif,
3729 gnumeric_averageif, NULL,
3730 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3731 { "averageifs", NULL, help_averageifs,
3732 NULL, gnumeric_averageifs,
3733 GNM_FUNC_SIMPLE,
3734 GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3735 { "minifs", NULL, help_minifs,
3736 NULL, gnumeric_minifs,
3737 GNM_FUNC_SIMPLE,
3738 GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3739 { "maxifs", NULL, help_maxifs,
3740 NULL, gnumeric_maxifs,
3741 GNM_FUNC_SIMPLE,
3742 GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3743 { "sumproduct", NULL, help_sumproduct,
3744 NULL, gnumeric_sumproduct,
3745 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3746 { "odf.sumproduct", NULL, help_odf_sumproduct,
3747 NULL, gnumeric_odf_sumproduct,
3748 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_NO_TESTSUITE },
3749 { "sumsq", NULL, help_sumsq,
3750 NULL, gnumeric_sumsq,
3751 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3752 { "sumx2my2", "AA", help_sumx2my2,
3753 gnumeric_sumx2my2, NULL,
3754 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3755 { "sumx2py2", "AA", help_sumx2py2,
3756 gnumeric_sumx2py2, NULL,
3757 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3758 { "sumxmy2", "AA", help_sumxmy2,
3759 gnumeric_sumxmy2, NULL,
3760 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3761 { "tan", "f", help_tan,
3762 gnumeric_tan, NULL,
3763 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3764 { "tanpi", "f", help_tanpi,
3765 gnumeric_tanpi, NULL,
3766 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3767 { "tanh", "f", help_tanh,
3768 gnumeric_tanh, NULL,
3769 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3770 { "trunc", "f|f", help_trunc,
3771 gnumeric_trunc, NULL,
3772 GNM_FUNC_SIMPLE + GNM_FUNC_AUTO_FIRST,
3773 GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3774 { "pi", "", help_pi,
3775 gnumeric_pi, NULL,
3776 GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_EXHAUSTIVE },
3777 { "mmult", "AA", help_mmult,
3778 gnumeric_mmult, NULL,
3779 GNM_FUNC_RETURNS_NON_SCALAR, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3780 { "minverse","A", help_minverse,
3781 gnumeric_minverse, NULL,
3782 GNM_FUNC_RETURNS_NON_SCALAR, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3783 { "mpseudoinverse","A|f", help_mpseudoinverse,
3784 gnumeric_mpseudoinverse, NULL,
3785 GNM_FUNC_RETURNS_NON_SCALAR, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC, GNM_FUNC_TEST_STATUS_NO_TESTSUITE },
3786 { "linsolve", "AA", help_linsolve,
3787 gnumeric_linsolve, NULL,
3788 GNM_FUNC_RETURNS_NON_SCALAR, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC, GNM_FUNC_TEST_STATUS_NO_TESTSUITE },
3789 { "mdeterm", "A", help_mdeterm,
3790 gnumeric_mdeterm, NULL,
3791 GNM_FUNC_RETURNS_NON_SCALAR, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
3792 { "munit","f", help_munit,
3793 gnumeric_munit, NULL,
3794 GNM_FUNC_RETURNS_NON_SCALAR, GNM_FUNC_IMPL_STATUS_COMPLETE,
3795 GNM_FUNC_TEST_STATUS_NO_TESTSUITE },
3796 { "eigen","A", help_eigen,
3797 gnumeric_eigen, NULL,
3798 GNM_FUNC_RETURNS_NON_SCALAR, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC, GNM_FUNC_TEST_STATUS_NO_TESTSUITE},
3799 #if 0
3800 { "logmdeterm", "A|si",
3801 help_logmdeterm, gnumeric_logmdeterm, NULL, NULL, NULL },
3802 #endif
3803 {NULL}
3804 };
3805
3806 G_MODULE_EXPORT void
go_plugin_init(GOPlugin * plugin,GOCmdContext * cc)3807 go_plugin_init (GOPlugin *plugin, GOCmdContext *cc)
3808 {
3809 g_signal_connect (gnm_func_lookup ("sumsq", NULL),
3810 "derivative", G_CALLBACK (gnumeric_sumsq_deriv), NULL);
3811 g_signal_connect (gnm_func_lookup ("exp", NULL),
3812 "derivative", G_CALLBACK (gnumeric_exp_deriv), NULL);
3813 g_signal_connect (gnm_func_lookup ("ln", NULL),
3814 "derivative", G_CALLBACK (gnumeric_ln_deriv), NULL);
3815 }
3816
3817 G_MODULE_EXPORT void
go_plugin_shutdown(GOPlugin * plugin,GOCmdContext * cc)3818 go_plugin_shutdown (GOPlugin *plugin, GOCmdContext *cc)
3819 {
3820 }
3821