Commit e7977dca authored by Arturo Espinosa's avatar Arturo Espinosa

oooooopsie

parent c875c8db
/*
* func.c: Built in mathematical functions and functions registration
* (C) 1998 The Free Software Foundation
*
* Author:
* Miguel de Icaza (miguel@gnu.org)
*/
#include <config.h>
#include <gnome.h>
#include "math.h"
#include "gnumeric.h"
#include "gnumeric-sheet.h"
#include "utils.h"
#include "func.h"
/* Some forward declarations */
static Value *gnumeric_sum (void *tsheet, GList *expr_node_list,
int eval_col, int eval_row,
char **error_string);
static Value *gnumeric_count (void *tsheet, GList *expr_node_list,
int eval_col, int eval_row,
char **error_string);
static Value *
gnumeric_abs (Value *argv [], char **error_string)
{
Value *v = g_new (Value, 1);
v->type = VALUE_FLOAT;
v->v.v_float = fabs (value_get_as_double (argv [0]));
return v;
}
static Value *
gnumeric_acos (Value *argv [], char **error_string)
{
Value *v;
float_t t;
t = value_get_as_double (argv [0]);
if ((t < -1.0) || (t > 1.0)){
*error_string = _("acos - domain error");
return NULL;
}
v = g_new (Value, 1);
v->type = VALUE_FLOAT;
v->v.v_float = acos (t);
return v;
}
static Value *
gnumeric_acosh (Value *argv [], char **error_string)
{
Value *v;
float_t t;
t = value_get_as_double (argv [0]);
if (t < 1.0){
*error_string = _("acosh - domain error");
return NULL;
}
v = g_new (Value, 1);
v->type = VALUE_FLOAT;
v->v.v_float = acosh (t);
return v;
}
static int
callback_function_and (Sheet *sheet, Value *value, char **error_string, void *closure)
{
Value *result = closure;
switch (value->type){
case VALUE_INTEGER:
if (value->v.v_int == 0){
result->v.v_int = 0;
return FALSE;
} else
result->v.v_int = 1;
break;
case VALUE_FLOAT:
if (value->v.v_float == 0.0){
result->v.v_int = 0;
return FALSE;
} else
result->v.v_int = 1;
default:
/* ignore strings */
}
return TRUE;
}
static char *help_and = {
N_("<function>AND</function>"
"<syntax>AND(b1, b2, ...)</syntax>n"
"<description>Implements the logical AND function: the result is TRUE "
"if all of the expression evaluate to TRUE, otherwise it returns "
"FALSE.<p>"
"b1, trough bN are expressions that should evaluate to TRUE or FALSE."
"If an integer or floating point value is provided zero is considered "
"FALSE and anything else is TRUE.<p>"
"If the values contain strings or empty cells those values are "
"ignored. If no logical values are provided, then the error '#VALUE!' "
"is returned. "
"</description>"
"<seealso>OR</seealso>")
};
static Value *
gnumeric_and (void *tsheet, GList *expr_node_list, int eval_col, int eval_row, char **error_string)
{
Value *result;
Sheet *sheet = (Sheet *) tsheet;
result = g_new (Value, 1);
result->type = VALUE_INTEGER;
result->v.v_int = -1;
function_iterate_argument_values (sheet, callback_function_and,
result, expr_node_list,
eval_col, eval_row, error_string);
/* See if there was any value worth using */
if (result->v.v_int == -1){
value_release (result);
*error_string = _("#VALUE");
return NULL;
}
return result;
}
static Value *
gnumeric_asin (Value *argv [], char **error_string)
{
Value *v;
float_t t;
t = value_get_as_double (argv [0]);
if ((t < -1.0) || (t > 1.0)){
*error_string = _("asin - domain error");
return NULL;
}
v = g_new (Value, 1);
v->type = VALUE_FLOAT;
v->v.v_float = asin (t);
return v;
}
static Value *
gnumeric_asinh (Value *argv [], char **error_string)
{
Value *v;
v = g_new (Value, 1);
v->type = VALUE_FLOAT;
v->v.v_float = asinh (value_get_as_double (argv [0]));
return v;
}
static Value *
gnumeric_atan (Value *argv [], char **error_string)
{
Value *v = g_new (Value, 1);
v->type = VALUE_FLOAT;
v->v.v_float = atan (value_get_as_double (argv [0]));
return v;
}
static Value *
gnumeric_atanh (Value *argv [], char **error_string)
{
Value *v = g_new (Value, 1);
float_t t;
t = value_get_as_double (argv [0]);
if ((t <= -1.0) || (t >= 1.0)){
*error_string = _("atanh: domain error");
return NULL;
}
v->type = VALUE_FLOAT;
v->v.v_float = atanh (value_get_as_double (argv [0]));
return v;
}
static Value *
gnumeric_atan2 (Value *argv [], char **error_string)
{
Value *v = g_new (Value, 1);
v->type = VALUE_FLOAT;
v->v.v_float = atan2 (value_get_as_double (argv [0]),
value_get_as_double (argv [1]));
return v;
}
static char *help_average = {
N_("<function>AVERAGE</function>"
"<syntax>AVERAGE(value1, value2,...)</syntax>"
"<description>"
"Computes the average of all the values and cells referenced in the "
"argument list. This is equivalent to the sum of the arguments divided "
"by the count of the arguments."
"</description>"
"<seealso>SUM, COUNT</seealso>")
};
static Value *
gnumeric_average (void *tsheet, GList *expr_node_list, int eval_col, int eval_row, char **error_string)
{
Value *result;
Value *sum, *count;
sum = gnumeric_sum (tsheet, expr_node_list, eval_col, eval_row, error_string);
if (!sum)
return NULL;
count = gnumeric_count (tsheet, expr_node_list, eval_col, eval_row, error_string);
if (!count){
value_release (sum);
return NULL;
}
result = g_new (Value, 1);
result->type = VALUE_FLOAT;
result->v.v_float = sum->v.v_float / count->v.v_int;
value_release (count);
value_release (sum);
return result;
}
static Value *
gnumeric_ceil (Value *argv [], char **error_string)
{
Value *v = g_new (Value, 1);
v->type = VALUE_FLOAT;
v->v.v_float = ceil (value_get_as_double (argv [0]));
return v;
}
static Value *
gnumeric_bin2dec (Value *argv [], char **error_string)
{
Value *value;
int result, v, n, bit;
char *p;
result = 0;
switch (argv [0]->type){
case VALUE_INTEGER:
v = argv [0]->v.v_int;
n = 0;
for (n = 0; v; n++){
bit = v % 10;
v = v / 10;
result |= bit << n;
}
break;
case VALUE_STRING:
p = argv [0]->v.str->str;
while (*p){
if (!(*p == '0' || *p == '1')){
*error_string = "#NUM!";
return NULL;
}
/* FIXME: implement */
result = *p;
}
break;
default:
*error_string = "#NUM!";
return NULL;
}
value = g_new (Value, 1);
value->type = VALUE_INTEGER;
value->v.v_int = result;
return value;
}
static Value *
gnumeric_cos (Value *argv [], char **error_string)
{
Value *v = g_new (Value, 1);
v->type = VALUE_FLOAT;
v->v.v_float = cos (value_get_as_double (argv [0]));
return v;
}
static Value *
gnumeric_cosh (Value *argv [], char **error_string)
{
Value *v = g_new (Value, 1);
v->type = VALUE_FLOAT;
v->v.v_float = cos (value_get_as_double (argv [0]));
return v;
}
static int
callback_function_count (Sheet *sheet, Value *value, char **error_string, void *closure)
{
Value *result = (Value *) closure;
switch (value->type){
case VALUE_INTEGER:
result->v.v_int++;
break;
case VALUE_FLOAT:
result->v.v_int++;
break;
default:
break;
}
return TRUE;
}
static Value *
gnumeric_count (void *tsheet, GList *expr_node_list, int eval_col, int eval_row, char **error_string)
{
Value *result;
Sheet *sheet = (Sheet *) tsheet;
result = g_new (Value, 1);
result->type = VALUE_INTEGER;
result->v.v_int = 0;
function_iterate_argument_values (sheet, callback_function_count, result, expr_node_list,
eval_col, eval_row, error_string);
return result;
}
static Value *
gnumeric_degrees (Value *argv [], char **error_string)
{
Value *v = g_new (Value, 1);
v->type = VALUE_FLOAT;
v->v.v_float = (value_get_as_double (argv [0]) * 180.0) / M_PI;
return v;
}
static Value *
gnumeric_exp (Value *argv [], char **error_string)
{
Value *v = g_new (Value, 1);
v->type = VALUE_FLOAT;
v->v.v_float = exp (value_get_as_double (argv [0]));
return v;
}
static Value *
gnumeric_floor (Value *argv [], char **error_string)
{
Value *v = g_new (Value, 1);
v->type = VALUE_FLOAT;
v->v.v_float = floor (value_get_as_double (argv [0]));
return v;
}
static Value *
gnumeric_int (Value *argv [], char **error_string)
{
Value *v = g_new (Value, 1);
float_t t;
t = value_get_as_double (argv [0]);
v->type = VALUE_FLOAT;
v->v.v_float = t > 0.0 ? floor (t) : ceil (t);
return v;
}
static Value *
gnumeric_log (Value *argv [], char **error_string)
{
Value *v;
float_t t;
t = value_get_as_double (argv [0]);
if (t < 0.0){
*error_string = _("log: domain error");
return NULL;
}
v = g_new (Value, 1);
v->type = VALUE_FLOAT;
v->v.v_float = log (t);
return v;
}
static Value *
gnumeric_log2 (Value *argv [], char **error_string)
{
Value *v;
float_t t;
t = value_get_as_double (argv [0]);
if (t < 0.0){
*error_string = _("log2: domain error");
return NULL;
}
v = g_new (Value, 1);
v->type = VALUE_FLOAT;
v->v.v_float = log (t) / M_LN2;
return v;
}
static Value *
gnumeric_log10 (Value *argv [], char **error_string)
{
Value *v;
float_t t;
t = value_get_as_double (argv [0]);
if (t < 0.0){
*error_string = _("log10: domain error");
return NULL;
}
v = g_new (Value, 1);
v->type = VALUE_FLOAT;
v->v.v_float = log10 (t);
return v;
}
static char *help_or = {
N_("<function>OR</function>"
"<syntax>OR(b1, b2, ...)</syntax>"
"<description>"
"Implements the logical OR function: the result is TRUE if any of the"
"values evaluated to TRUE.<p>"
"b1, trough bN are expressions that should evaluate to TRUE or FALSE."
"If an integer or floating point value is provided zero is considered"
"FALSE and anything else is TRUE.<p>"
"If the values contain strings or empty cells those values are "
"ignored. If no logical values are provided, then the error '#VALUE!'"
"is returned."
"</description>"
"<seealso>AND</seealso>")
};
static int
callback_function_or (Sheet *sheet, Value *value, char **error_string, void *closure)
{
Value *result = closure;
switch (value->type){
case VALUE_INTEGER:
if (value->v.v_int == 1){
result->v.v_int = 1;
return FALSE;
} else
result->v.v_int = 0;
break;
case VALUE_FLOAT:
if (value->v.v_float == 0.0){
result->v.v_int = 1;
return FALSE;
} else
result->v.v_int = 0;
default:
/* ignore strings */
}
return TRUE;
}
static Value *
gnumeric_or (void *tsheet, GList *expr_node_list, int eval_col, int eval_row, char **error_string)
{
Value *result;
Sheet *sheet = (Sheet *) tsheet;
result = g_new (Value, 1);
result->type = VALUE_INTEGER;
result->v.v_int = -1;
function_iterate_argument_values (sheet, callback_function_or,
result, expr_node_list,
eval_col, eval_row, error_string);
/* See if there was any value worth using */
if (result->v.v_int == -1){
value_release (result);
*error_string = _("#VALUE");
return NULL;
}
return result;
}
static Value *
gnumeric_radians (Value *argv [], char **error_string)
{
Value *v = g_new (Value, 1);
v->type = VALUE_FLOAT;
v->v.v_float = (value_get_as_double (argv [0]) * M_PI) / 180;
return v;
}
static Value *
gnumeric_sin (Value *argv [], char **error_string)
{
Value *v = g_new (Value, 1);
v->type = VALUE_FLOAT;
v->v.v_float = sin (value_get_as_double (argv [0]));
return v;
}
static Value *
gnumeric_sinh (Value *argv [], char **error_string)
{
Value *v = g_new (Value, 1);
v->type = VALUE_FLOAT;
v->v.v_float = sinh (value_get_as_double (argv [0]));
return v;
}
static int
callback_function_sum (Sheet *sheet, Value *value, char **error_string, void *closure)
{
Value *result = (Value *) closure;
switch (value->type){
case VALUE_INTEGER:
result->v.v_float += value->v.v_int;
break;
case VALUE_FLOAT:
result->v.v_float += value->v.v_float;
break;
case VALUE_STRING:
result->v.v_float += atof (value->v.str->str);
break;
default:
g_warning ("Unknown VALUE type in callback_function_sum");
break;
}
return TRUE;
}
static Value *
gnumeric_sum (void *tsheet, GList *expr_node_list, int eval_col, int eval_row, char **error_string)
{
Value *result;
Sheet *sheet = (Sheet *) tsheet;
result = g_new (Value, 1);
result->type = VALUE_FLOAT;
result->v.v_float = 0.0;
function_iterate_argument_values (sheet, callback_function_sum, result, expr_node_list,
eval_col, eval_row, error_string);
return result;
}
static Value *
gnumeric_tan (Value *argv [], char **error_string)
{
Value *v = g_new (Value, 1);
v->type = VALUE_FLOAT;
v->v.v_float = tan (value_get_as_double (argv [0]));
return v;
}
static Value *
gnumeric_tanh (Value *argv [], char **error_string)
{
Value *v = g_new (Value, 1);
v->type = VALUE_FLOAT;
v->v.v_float = tanh (value_get_as_double (argv [0]));
return v;
}
static Value *
gnumeric_pi (Value *argv [], char **error_string)
{
Value *v = g_new (Value, 1);
v->type = VALUE_FLOAT;
v->v.v_float = M_PI;
return v;
}
FunctionDefinition math_functions [] = {
{ "abs", "f", "number", NULL, NULL, gnumeric_abs },
{ "acos", "f", "number", NULL, NULL, gnumeric_acos },
{ "acosh", "f", "number", NULL, NULL, gnumeric_acosh },
{ "and", 0, "", &help_and, gnumeric_and, NULL },
{ "asin", "f", "number", NULL, NULL, gnumeric_asin },
{ "asinh", "f", "number", NULL, NULL, gnumeric_asinh },
{ "atan", "f", "number", NULL, NULL, gnumeric_atan },