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