Commit 6f3de14a authored by Jukka-Pekka Iivonen's avatar Jukka-Pekka Iivonen Committed by jpekka

Made GCD() to take variable number of arguments.

1999-06-16  Jukka-Pekka Iivonen  <iivonen@iki.fi>

	* src/fn-math.c (gnumeric_gcd): Made GCD() to take variable number
 	of arguments.

	* src/fn-stat.c (gnumeric_rank): RANK() fixed.

	* src/fn-eng.c (gnumeric_erf): ERF() fixed to return negative
	results if the argument is negative too like in Excel.

	* srg/fn-eng.c (get_real_and_imaginary): Added a branch for empty
 	imaginary part.

	* src/fn-eng.c (gnumeric_improduct, gnumeric_imsum): Made IMSUM()
	and IMPRODUCT() to take variable number of arguments.
parent cf1c7da3
Changes between version 0.26 and 0.27
Jukka has added the following functions:
* SEARCH(), ADDRESS(), CHITEST(), BETAINV(), PERCENTRANK(),
* SERIESSUM(), SUMA(), SUBTOTAL(), SLOPE(), AVERAGEA(),
* MAXA(), MINA(), STDEVA(), STDEVPA(), VARA(), and VARPA().
And fixed these:
* BETADIST(), NORMDIST(), and POISSON().
Jukka:
* Added the following functions:
- SEARCH(), ADDRESS(), CHITEST(), BETAINV(), PERCENTRANK(),
SERIESSUM(), SUMA(), SUBTOTAL(), SLOPE(), AVERAGEA(),
MAXA(), MINA(), STDEVA(), STDEVPA(), VARA(), and VARPA().
* And fixed these functions:
- BETADIST(), NORMDIST(), RANK(), and POISSON().
Morten:
* Found everyone else's bugs.
......
1999-06-16 Jukka-Pekka Iivonen <iivonen@iki.fi>
* src/fn-math.c (gnumeric_gcd): Made GCD() to take variable number
of arguments.
* src/fn-stat.c (gnumeric_rank): RANK() fixed.
* src/fn-eng.c (gnumeric_erf): ERF() fixed to return negative
results if the argument is negative too like in Excel.
* srg/fn-eng.c (get_real_and_imaginary): Added a branch for empty
imaginary part.
* src/fn-eng.c (gnumeric_improduct, gnumeric_imsum): Made IMSUM()
and IMPRODUCT() to take variable number of arguments.
1999-06-15 Morten Welinder <terra@diku.dk>
* src/style.c (style_font_new_simple): Plug leak.
......
1999-06-16 Jukka-Pekka Iivonen <iivonen@iki.fi>
* src/fn-math.c (gnumeric_gcd): Made GCD() to take variable number
of arguments.
* src/fn-stat.c (gnumeric_rank): RANK() fixed.
* src/fn-eng.c (gnumeric_erf): ERF() fixed to return negative
results if the argument is negative too like in Excel.
* srg/fn-eng.c (get_real_and_imaginary): Added a branch for empty
imaginary part.
* src/fn-eng.c (gnumeric_improduct, gnumeric_imsum): Made IMSUM()
and IMPRODUCT() to take variable number of arguments.
1999-06-15 Morten Welinder <terra@diku.dk>
* src/style.c (style_font_new_simple): Plug leak.
......
1999-06-16 Jukka-Pekka Iivonen <iivonen@iki.fi>
* src/fn-math.c (gnumeric_gcd): Made GCD() to take variable number
of arguments.
* src/fn-stat.c (gnumeric_rank): RANK() fixed.
* src/fn-eng.c (gnumeric_erf): ERF() fixed to return negative
results if the argument is negative too like in Excel.
* srg/fn-eng.c (get_real_and_imaginary): Added a branch for empty
imaginary part.
* src/fn-eng.c (gnumeric_improduct, gnumeric_imsum): Made IMSUM()
and IMPRODUCT() to take variable number of arguments.
1999-06-15 Morten Welinder <terra@diku.dk>
* src/style.c (style_font_new_simple): Plug leak.
......
1999-06-16 Jukka-Pekka Iivonen <iivonen@iki.fi>
* src/fn-math.c (gnumeric_gcd): Made GCD() to take variable number
of arguments.
* src/fn-stat.c (gnumeric_rank): RANK() fixed.
* src/fn-eng.c (gnumeric_erf): ERF() fixed to return negative
results if the argument is negative too like in Excel.
* srg/fn-eng.c (get_real_and_imaginary): Added a branch for empty
imaginary part.
* src/fn-eng.c (gnumeric_improduct, gnumeric_imsum): Made IMSUM()
and IMPRODUCT() to take variable number of arguments.
1999-06-15 Morten Welinder <terra@diku.dk>
* src/style.c (style_font_new_simple): Plug leak.
......
1999-06-16 Jukka-Pekka Iivonen <iivonen@iki.fi>
* ms-formula-read.c (formula_func_data): SUMIF made var args.
1999-06-15 Morten Welinder <terra@diku.dk>
* ms-formula-read.c (ms_excel_parse_formula): Handle bools. Plug
......
......@@ -419,7 +419,7 @@ FORMULA_FUNC_DATA formula_func_data[] =
/* 342 */ { "RADIANS", 1 },
/* 343 */ { "DEGREES", 1 },
/* 344 */ { "SUBTOTAL", -1 },
/* 345 */ { "SUMIF", 3 },
/* 345 */ { "SUMIF", -1 }, /* Actual range is optional */
/* 346 */ { "COUNTIF", 2 },
/* 347 */ { "COUNTBLANK", -1 },
/* 348 */ { "SCENARIOGET", -2 },
......
......@@ -505,6 +505,7 @@ get_real_and_imaginary(char *inumber, float_t *real, float_t *im,
char *p;
*real = 0;
*suffix = j_suffix;
*im = is_unit_imaginary(inumber, suffix);
if (*im)
......@@ -515,6 +516,11 @@ get_real_and_imaginary(char *inumber, float_t *real, float_t *im,
if (inumber == p)
return 1;
if (*p == '\0') {
*im = 0;
return 0;
}
/* Check if only imaginary coefficient */
if (*p == 'i') {
if (*(p+1) == '\0') {
......@@ -1199,45 +1205,114 @@ gnumeric_imsub (struct FunctionDefinition *fd,
static char *help_improduct = {
N_("@FUNCTION=IMPRODUCT\n"
"@SYNTAX=IMPRODUCT(inumber,inumber)\n"
"@SYNTAX=IMPRODUCT(inumber1[,inumber2,...])\n"
"@DESCRIPTION="
"IMPRODUCT returns the product of two complex numbers. "
"IMPRODUCT returns the product of given complex numbers. "
"\n"
"@SEEALSO=IMDIV")
};
static Value *
gnumeric_improduct (struct FunctionDefinition *fd,
Value *argv [], char **error_string)
typedef enum {
Improduct, Imsum
} eng_imoper_type_t;
typedef struct {
float_t real;
float_t im;
char *suffix;
eng_imoper_type_t type;
} eng_imoper_t;
static int
callback_function_imoper (Sheet *sheet, Value *value,
char **error_string, void *closure)
{
float_t a, b, c, d;
char *suffix;
eng_imoper_t *result = closure;
char *suffix;
float_t im, real, rest_im, rest_real;
if (VALUE_IS_NUMBER(argv[0])) {
a = value_get_as_float (argv[0]);
b = 0;
} else if (argv[0]->type != VALUE_STRING) {
*error_string = gnumeric_err_VALUE;
return NULL;
} else if (get_real_and_imaginary(argv[0]->v.str->str,
&a, &b, &suffix)) {
*error_string = gnumeric_err_NUM;
return NULL;
switch (value->type){
case VALUE_INTEGER:
im = 0;
real = value->v.v_int;
break;
case VALUE_FLOAT:
im = 0;
real = value->v.v_float;
break;
case VALUE_STRING:
if (get_real_and_imaginary(value->v.str->str,
&real, &im, &suffix))
return FALSE;
break;
default:
return FALSE;
}
rest_real = result->real;
rest_im = result->im;
switch (result->type) {
case Improduct:
result->real = rest_real*real - rest_im*im;
result->im = rest_real*im + rest_im*real;
break;
case Imsum:
result->real = rest_real + real;
result->im = rest_im + im;
break;
default:
return FALSE;
}
if (VALUE_IS_NUMBER(argv[1])) {
c = value_get_as_float (argv[1]);
d = 0;
} else if (argv[1]->type != VALUE_STRING) {
return TRUE;
}
static Value *
gnumeric_improduct (Sheet *sheet, GList *expr_node_list,
int eval_col, int eval_row, char **error_string)
{
eng_imoper_t p;
ExprTree *tree;
Value *val;
float_t a, b;
if (expr_node_list == NULL) {
*error_string = gnumeric_err_NUM;
return NULL;
}
tree = (ExprTree *) expr_node_list->data;
if (tree == NULL) {
*error_string = gnumeric_err_NUM;
return NULL;
}
val = eval_expr (sheet, tree, eval_col, eval_row, error_string);
if (VALUE_IS_NUMBER(val)) {
p.real = value_get_as_float (val);
p.im = 0;
p.suffix = "j";
} else if (val->type != VALUE_STRING) {
*error_string = gnumeric_err_VALUE;
return NULL;
} else if (get_real_and_imaginary(argv[1]->v.str->str,
&c, &d, &suffix)) {
} else if (get_real_and_imaginary(val->v.str->str,
&p.real, &p.im, &p.suffix)) {
*error_string = gnumeric_err_NUM;
return NULL;
}
return create_inumber (a*c-b*d, a*d+b*c, suffix);
p.type = Improduct;
if (function_iterate_argument_values (sheet, callback_function_imoper,
&p, expr_node_list->next,
eval_col, eval_row,
error_string) == FALSE) {
*error_string = gnumeric_err_NUM;
return NULL;
}
return create_inumber (p.real, p.im, p.suffix);
}
static char *help_imsum = {
......@@ -1250,37 +1325,50 @@ static char *help_imsum = {
};
static Value *
gnumeric_imsum (struct FunctionDefinition *fd,
Value *argv [], char **error_string)
gnumeric_imsum (Sheet *sheet, GList *expr_node_list,
int eval_col, int eval_row, char **error_string)
{
float_t a, b, c, d;
char *suffix;
if (VALUE_IS_NUMBER(argv[0])) {
a = value_get_as_float (argv[0]);
b = 0;
} else if (argv[0]->type != VALUE_STRING) {
*error_string = gnumeric_err_VALUE;
return NULL;
} else if (get_real_and_imaginary(argv[0]->v.str->str,
&a, &b, &suffix)) {
*error_string = gnumeric_err_NUM;
return NULL;
eng_imoper_t p;
ExprTree *tree;
Value *val;
float_t a, b;
if (expr_node_list == NULL) {
*error_string = gnumeric_err_NUM;
return NULL;
}
if (VALUE_IS_NUMBER(argv[1])) {
c = value_get_as_float (argv[1]);
d = 0;
} else if (argv[1]->type != VALUE_STRING) {
tree = (ExprTree *) expr_node_list->data;
if (tree == NULL) {
*error_string = gnumeric_err_NUM;
return NULL;
}
val = eval_expr (sheet, tree, eval_col, eval_row, error_string);
if (VALUE_IS_NUMBER(val)) {
p.real = value_get_as_float (val);
p.im = 0;
p.suffix = "j";
} else if (val->type != VALUE_STRING) {
*error_string = gnumeric_err_VALUE;
return NULL;
} else if (get_real_and_imaginary(argv[1]->v.str->str,
&c, &d, &suffix)) {
} else if (get_real_and_imaginary(val->v.str->str,
&p.real, &p.im, &p.suffix)) {
*error_string = gnumeric_err_NUM;
return NULL;
}
return create_inumber (a+c, b+d, suffix);
p.type = Imsum;
if (function_iterate_argument_values (sheet, callback_function_imoper,
&p, expr_node_list->next,
eval_col, eval_row,
error_string) == FALSE) {
*error_string = gnumeric_err_NUM;
return NULL;
}
return create_inumber (p.real, p.im, p.suffix);
}
static char *help_convert = {
......@@ -1700,15 +1788,16 @@ gnumeric_erf (struct FunctionDefinition *i,
lower = value_get_as_float (argv[0]);
if (argv[1])
upper = value_get_as_float (argv[1]);
if (lower < 0.0 || upper < 0.0){
*error_string = gnumeric_err_NUM;
return NULL;
}
ans = erf(lower);
if (lower < 0.0)
ans = -erf(-lower);
else
ans = erf(lower);
if (argv[1])
ans = erf(upper) - ans;
if (upper < 0.0)
ans = -erf(-upper) - ans;
else
ans = erf(upper) - ans;
return value_new_float (ans);
}
......@@ -1942,8 +2031,8 @@ FunctionDefinition eng_functions [] = {
NULL, gnumeric_imlog2 },
{ "impower", "?f", "inumber,number", &help_impower,
NULL, gnumeric_impower },
{ "improduct", "??", "inumber,inumber", &help_improduct,
NULL, gnumeric_improduct },
{ "improduct", 0, "inumber1,inumber2,...", &help_improduct,
gnumeric_improduct, NULL },
{ "imreal", "?", "inumber", &help_imreal,
NULL, gnumeric_imreal },
{ "imsin", "?", "inumber", &help_imsin,
......@@ -1953,7 +2042,7 @@ FunctionDefinition eng_functions [] = {
{ "imsub", "??", "inumber,inumber", &help_imsub,
NULL, gnumeric_imsub },
{ "imsum", "??", "inumber,inumber", &help_imsum,
NULL, gnumeric_imsum },
gnumeric_imsum, NULL },
{ "oct2bin", "?|f", "xnum,ynum", &help_oct2bin,
NULL, gnumeric_oct2bin },
{ "oct2dec", "?", "number", &help_oct2dec,
......
......@@ -109,6 +109,33 @@ callback_function_sumxy (Sheet *sheet, int col, int row,
return TRUE;
}
static int
callback_function_makeslist (Sheet *sheet, Value *value,
char **error_string, void *closure)
{
math_sums_t *mm = closure;
float_t x;
gpointer p;
switch (value->type) {
case VALUE_INTEGER:
x = value->v.v_int;
break;
case VALUE_FLOAT:
x = value->v.v_float;
break;
default:
return TRUE;
}
p = g_new(float_t, 1);
*((float_t *) p) = x;
mm->list = g_slist_append(mm->list, p);
mm->num++;
return TRUE;
}
typedef struct {
GSList *list;
criteria_test_fun_t fun;
......@@ -151,10 +178,10 @@ callback_function_criteria (Sheet *sheet, int col, int row,
static char *help_gcd = {
N_("@FUNCTION=GCD\n"
"@SYNTAX=GCD(a,b)\n"
"@SYNTAX=GCD(number1,number2,...)\n"
"@DESCRIPTION="
"GCD returns the greatest common divisor of two numbers. "
"GCD returns the greatest common divisor of given numbers. "
"\n"
"If any of the arguments is less than zero, GCD returns #NUM! "
"error. "
......@@ -163,20 +190,55 @@ static char *help_gcd = {
};
static Value *
gnumeric_gcd (struct FunctionDefinition *i,
Value *argv [], char **error_string)
gnumeric_gcd (Sheet *sheet, GList *expr_node_list,
int eval_col, int eval_row, char **error_string)
{
float_t a, b;
math_sums_t p;
GSList *current;
int a, b, old_gcd, new_gcd;
a = value_get_as_float (argv[0]);
b = value_get_as_float (argv[1]);
p.num = 0;
p.list = NULL;
if (function_iterate_argument_values (sheet,
callback_function_makeslist,
&p, expr_node_list,
eval_col, eval_row,
error_string) == FALSE) {
*error_string = gnumeric_err_NUM;
return NULL;
}
if (a < 0 || b < 0) {
if (p.list == NULL || p.list->next == NULL) {
*error_string = gnumeric_err_NUM;
return NULL;
}
return value_new_int (gcd(a, b));
try_again:
a = *((float_t *) p.list->data);
current=p.list->next;
b = *((float_t *) current->data);
old_gcd = gcd(a, b);
for (current=current->next; current!=NULL; current=current->next) {
b = *((float_t *) current->data);
new_gcd = gcd(a, b);
if (old_gcd != new_gcd) {
GSList *tmp;
for (tmp=p.list; tmp!=NULL; tmp=tmp->next) {
b = *((float_t *) current->data);
if (b % old_gcd == 0)
*((float_t *) current->data) =
b / old_gcd;
}
goto try_again;
}
}
for (current=p.list; current!=NULL; current=current->next)
g_free(current->data);
g_slist_free(p.list);
return value_new_int (old_gcd);
}
static char *help_lcm = {
......@@ -1769,7 +1831,6 @@ gnumeric_randbetween (struct FunctionDefinition *i,
return value_new_float (r);
}
static char *help_rounddown = {
N_("@FUNCTION=ROUNDDOWN\n"
"@SYNTAX=ROUNDDOWN(number[,digits])\n"
......@@ -2550,7 +2611,7 @@ FunctionDefinition math_functions [] = {
NULL, gnumeric_combin },
{ "floor", "f|f", "number", &help_floor, NULL, gnumeric_floor },
{ "gcd", "ff", "number1,number2", &help_gcd,
NULL, gnumeric_gcd },
gnumeric_gcd, NULL },
{ "int", "f", "number", &help_int, NULL, gnumeric_int },
{ "lcm", 0, "", &help_lcm, gnumeric_lcm, NULL },
{ "ln", "f", "number", &help_ln, NULL, gnumeric_ln },
......
......@@ -332,7 +332,7 @@ callback_function_stat_inv_sum (Sheet *sheet, Value *value,
static char *help_rank = {
N_("@FUNCTION=RANK\n"
"@SYNTAX=RANK(x,ref,order)\n"
"@SYNTAX=RANK(x,ref[,order])\n"
"@DESCRIPTION="
"RANK returns the rank of a number in a list of numbers. @x is the "
......@@ -345,75 +345,71 @@ static char *help_rank = {
};
typedef struct {
int first;
guint32 num;
float_t x;
float_t last;
GSList *list;
int order;
int rank;
} stat_rank_t;
static int
callback_function_rank (Sheet *sheet, Value *value,
char **error_string, void *closure)
callback_function_rank (Sheet *sheet, int col, int row,
Cell *cell, void *user_data)
{
stat_rank_t *mm = closure;
float_t x;
stat_rank_t *p = user_data;
float_t x;
if (!VALUE_IS_NUMBER (value))
return TRUE;
if (cell == NULL || cell->value == NULL)
return TRUE;
x = value_get_as_float (value);
if (mm->first == TRUE)
mm->x = x;
else if (mm->num == 1)
mm->last = x;
else {
float_t *p = g_new (float_t, 1);
*p = mm->last;
mm->list = g_slist_append (mm->list, p);
mm->last = x;
switch (cell->value->type) {
case VALUE_INTEGER:
x = cell->value->v.v_int;
break;
case VALUE_FLOAT:
x = cell->value->v.v_float;
break;
default:
return FALSE;
}
if (p->order) {
if (x < p->x)
p->rank++;
} else {
if (x > p->x)
p->rank++;
}
mm->num++;
mm->first = FALSE;
return TRUE;
}
static Value *
gnumeric_rank (Sheet *sheet, GList *expr_node_list,
int eval_col, int eval_row, char **error_string)
gnumeric_rank (struct FunctionDefinition *i,
Value *argv [], char **error_string)
{
stat_rank_t p;
GSList *list;
int order, rank;
p.first = TRUE;
p.num = 0;
p.list = NULL;
int ret;
function_iterate_argument_values (sheet, callback_function_rank,
&p, expr_node_list,
eval_col, eval_row, error_string);
list = p.list;
order = (int) p.last;
rank = 1;
p.x = value_get_as_float (argv[0]);
if (argv[2])
p.order = value_get_as_int (argv[2]);
else
p.order = 0;
p.rank = 1;
ret = sheet_cell_foreach_range (
argv[1]->v.cell_range.cell_a.sheet, TRUE,
argv[1]->v.cell_range.cell_a.col,
argv[1]->v.cell_range.cell_a.row,
argv[1]->v.cell_range.cell_b.col,
argv[1]->v.cell_range.cell_b.row,
callback_function_rank,
&p);
while (list != NULL){
float_t *x;
x = list->data;
if (order){
if (*x < p.x)
rank++;
} else {
if (*x > p.x)
rank++;
}
g_free(x);
list = list->next;
if (ret == FALSE) {
*error_string = gnumeric_err_VALUE;
return NULL;
}
g_slist_free(p.list);
return value_new_int (rank);
return value_new_int (p.rank);
}
static char *help_trimmean = {
......@@ -1113,8 +1109,7 @@ static char *help_counta = {
static int
callback_function_counta (Sheet *sheet, Value *value,
char **error_string, void *
closure)
char **error_string, void *closure)
{
Value *result = (Value *) closure;
......@@ -4015,8 +4010,8 @@ FunctionDefinition stat_functions [] = {
gnumeric_pearson, NULL },
{ "prob", "AAf|f", "x_range,prob_range,lower_limit,upper_limit",
&help_prob, NULL, gnumeric_prob },
{ "rank", 0, "", &help_rank,
gnumeric_rank, NULL },
{ "rank", "fr|f", "number,range[,order]", &help_rank,
NULL, gnumeric_rank },
{ "rsq", 0, "", &help_rsq,
gnumeric_rsq, NULL },
{ "skew", 0, "", &help_skew,
......
......@@ -505,6 +505,7 @@ get_real_and_imaginary(char *inumber, float_t *real, float_t *im,
char *p;
*real = 0;
*suffix = j_suffix;
*im = is_unit_imaginary(inumber, suffix);
if (*im)
......@@ -515,6 +516,11 @@ get_real_and_imaginary(char *inumber, float_t *real, float_t *im,
if (inumber == p)
return 1;
if (*p == '\0') {
*im = 0;
return 0;
}
/* Check if only imaginary coefficient */
if (*p == 'i') {
if (*(p+1) == '\0') {
......@@ -1199,45 +1205,114 @@ gnumeric_imsub (struct FunctionDefinition *fd,
static char *help_improduct = {
N_("@FUNCTION=IMPRODUCT\n"
"@SYNTAX=IMPRODUCT(inumber,inumber)\n"
"@SYNTAX=IMPRODUCT(inumber1[,inumber2,...])\n"
"@DESCRIPTION="
"IMPRODUCT returns the product of two complex numbers. "
"IMPRODUCT returns the product of given complex numbers. "
"\n"
"@SEEALSO=IMDIV")
};
static Value *
gnumeric_improduct (struct FunctionDefinition *fd,
Value *argv [], char **error_string)
typedef enum {
Improduct, Imsum
} eng_imoper_type_t;
typedef struct {
float_t real;
float_t im;
char *suffix;
eng_imoper_type_t type;
} eng_imoper_t;
static int
callback_function_imoper (Sheet *sheet, Value *value,
char **error_string, void *closure)
{
float_t a, b, c, d;
char *suffix;