Commit 7d5254f8 authored by jpekka's avatar jpekka
Browse files

Back to 1.49.

parent 2050bd9f
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* fn-complex.c: Built in complex number functions and functions registration
* fn-logical.c: Built in logical functions and functions registration
*
* Authors:
* Michael Meeks <michael@imaginator.com>
* Miguel de Icaza (miguel@gnu.org)
* Jukka-Pekka Iivonen (iivonen@iki.fi)
* Morten Welinder (terra@diku.dk)
*
......@@ -26,1268 +26,337 @@
#include <gnumeric.h>
#include <func.h>
#include <complex.h>
#include <parse-util.h>
#include <cell.h>
#include <expr.h>
#include <value.h>
#include <auto-format.h>
#include <libgnome/gnome-i18n.h>
#include <mathfunc.h>
#include "plugin.h"
#include "plugin-util.h"
#include "module-plugin-defs.h"
#include "gsl-complex.h"
GNUMERIC_MODULE_PLUGIN_INFO_DECL;
/* Converts a complex number string into its coefficients. Returns 0 if ok,
* 1 if an error occurred.
*/
static int
value_get_as_complex (Value *val, complex_t *res, char *imunit)
{
if (VALUE_IS_NUMBER (val)) {
complex_real (res, value_get_as_float (val));
*imunit = 'i';
return 0;
} else {
return complex_from_string (res,
value_peek_string (val),
imunit);
}
}
static Value *
value_new_complex (const complex_t *c, char imunit)
{
if (complex_real_p (c))
return value_new_float (c->re);
else {
char *s, f[5 + 4 * sizeof (int) + strlen (GNUM_FORMAT_g)];
Value *res;
sprintf (f, "%%.%d" GNUM_FORMAT_g, GNUM_DIG);
s = complex_to_string (c, f, f, imunit);
res = value_new_string (s);
g_free (s);
return res;
}
}
/***************************************************************************/
static const char *help_complex = {
N_("@FUNCTION=COMPLEX\n"
"@SYNTAX=COMPLEX(real,im[,suffix])\n"
"@DESCRIPTION="
"COMPLEX returns a complex number of the form x + yi. "
"@real is the real and @im is the imaginary coefficient of "
"the complex number. @suffix is the suffix for the imaginary "
"coefficient. If it is omitted, COMPLEX uses 'i' by default."
"\n"
"If @suffix is neither 'i' nor 'j', COMPLEX returns #VALUE! "
"error.\n"
"This function is Excel compatible. "
"\n"
"@EXAMPLES=\n"
"COMPLEX(1,-1) equals 1-i.\n"
"\n"
"@SEEALSO=")
};
static Value *
gnumeric_complex (FunctionEvalInfo *ei, Value **argv)
{
complex_t c;
const char *suffix;
complex_init (&c,
value_get_as_float (argv[0]),
value_get_as_float (argv[1]));
suffix = argv[2] ? value_peek_string (argv[2]) : "i";
if (strcmp (suffix, "i") != 0 && strcmp (suffix, "j") != 0)
return value_new_error (ei->pos, gnumeric_err_VALUE);
return value_new_complex (&c, *suffix);
}
/***************************************************************************/
static const char *help_imaginary = {
N_("@FUNCTION=IMAGINARY\n"
"@SYNTAX=IMAGINARY(inumber)\n"
"@DESCRIPTION="
"IMAGINARY returns the imaginary coefficient of a complex "
"number.\n"
"This function is Excel compatible. "
"\n"
"@EXAMPLES=\n"
"IMAGINARY(\"132-j\") equals -1.\n"
"\n"
"@SEEALSO=IMREAL")
};
static Value *
gnumeric_imaginary (FunctionEvalInfo *ei, Value **argv)
{
complex_t c;
char imunit;
if (VALUE_IS_NUMBER (argv[0]))
return value_new_float (0.0);
if (value_get_as_complex (argv[0], &c, &imunit))
return value_new_error (ei->pos, gnumeric_err_VALUE);
return value_new_float (c.im);
}
/***************************************************************************/
static const char *help_imabs = {
N_("@FUNCTION=IMABS\n"
"@SYNTAX=IMABS(inumber)\n"
"@DESCRIPTION="
"IMABS returns the absolute value of a complex number.\n"
"This function is Excel compatible. "
"\n"
"@EXAMPLES=\n"
"IMABS(\"2-j\") equals 2.23606798.\n"
"\n"
"@SEEALSO=IMAGINARY,IMREAL")
};
static Value *
gnumeric_imabs (FunctionEvalInfo *ei, Value **argv)
{
complex_t c;
char imunit;
if (value_get_as_complex (argv[0], &c, &imunit))
return value_new_error (ei->pos, gnumeric_err_VALUE);
if (argv[0]->type != VALUE_STRING)
return value_new_error (ei->pos, gnumeric_err_VALUE);
return value_new_float (complex_mod (&c));
}
/***************************************************************************/
static const char *help_and = {
N_("@FUNCTION=AND\n"
"@SYNTAX=AND(b1, b2, ...)\n"
static const char *help_imreal = {
N_("@FUNCTION=IMREAL\n"
"@SYNTAX=IMREAL(inumber)\n"
"@DESCRIPTION="
"IMREAL returns the real coefficient of a complex number.\n"
"This function is Excel compatible. "
"\n"
"@EXAMPLES=\n"
"imreal(\"132-j\") equals 132.\n"
"\n"
"@SEEALSO=IMAGINARY")
};
static Value *
gnumeric_imreal (FunctionEvalInfo *ei, Value **argv)
{
complex_t c;
char imunit;
"AND implements the logical AND function: the result is TRUE "
"if all of the expressions evaluate to TRUE, otherwise it returns "
"FALSE.\n"
if (VALUE_IS_NUMBER (argv[0]))
return value_duplicate (argv[0]);
if (value_get_as_complex (argv[0], &c, &imunit))
return value_new_error (ei->pos, gnumeric_err_VALUE);
"@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.\n"
return value_new_float (c.re);
}
/***************************************************************************/
static const char *help_imconjugate = {
N_("@FUNCTION=IMCONJUGATE\n"
"@SYNTAX=IMCONJUGATE(inumber)\n"
"@DESCRIPTION="
"IMCONJUGATE returns the complex conjugate of a complex number.\n"
"If the values contain strings or empty cells those values are "
"ignored. "
"If no logical values are provided, then the error #VALUE! "
"is returned.\n"
"This function is Excel compatible. "
"\n"
"@EXAMPLES=\n"
"IMCONJUGATE(\"1-j\") equals 1+j.\n"
"\n"
"@SEEALSO=IMAGINARY,IMREAL")
};
static Value *
gnumeric_imconjugate (FunctionEvalInfo *ei, Value **argv)
{
complex_t c, res;
char imunit;
if (value_get_as_complex (argv[0], &c, &imunit))
return value_new_error (ei->pos, gnumeric_err_VALUE);
if (argv[0]->type != VALUE_STRING)
return value_new_error (ei->pos, gnumeric_err_VALUE);
complex_conj (&res, &c);
return value_new_complex (&res, imunit);
}
/***************************************************************************/
static const char *help_imcos = {
N_("@FUNCTION=IMCOS\n"
"@SYNTAX=IMCOS(inumber)\n"
"@DESCRIPTION="
"IMCOS returns the cosine of a complex number.\n"
"This function is Excel compatible."
"\n"
"@EXAMPLES=\n"
"IMCOS(\"1+j\") equals 0.833730-0.988898j.\n"
"AND(TRUE,TRUE) equals TRUE.\n"
"AND(TRUE,FALSE) equals FALSE.\n\n"
"Let us assume that A1 holds number five and A2 number one. Then\n"
"AND(A1>3,A2<2) equals TRUE.\n"
"\n"
"@SEEALSO=IMSIN,IMTAN")
"@SEEALSO=OR, NOT")
};
static Value *
gnumeric_imcos (FunctionEvalInfo *ei, Value **argv)
callback_function_and (const EvalPos *ep, Value *value, void *closure)
{
complex_t c, res;
char imunit;
int *result = closure;
gboolean err;
if (value_get_as_complex (argv[0], &c, &imunit))
return value_new_error (ei->pos, gnumeric_err_VALUE);
*result = value_get_as_bool (value, &err) && *result;
if (err)
return value_new_error (ep, gnumeric_err_VALUE);
complex_cos (&res, &c);
return value_new_complex (&res, imunit);
return NULL;
}
/***************************************************************************/
static const char *help_imtan = {
N_("@FUNCTION=IMTAN\n"
"@SYNTAX=IMTAN(inumber)\n"
"@DESCRIPTION="
"IMTAN returns the tangent of a complex number.\n"
"This function is Excel compatible. "
"\n"
"@EXAMPLES=\n"
"\n"
"@SEEALSO=IMSIN,IMCOS")
};
static Value *
gnumeric_imtan (FunctionEvalInfo *ei, Value **argv)
gnumeric_and (FunctionEvalInfo *ei, GnmExprList *nodes)
{
complex_t c, res;
char imunit;
if (value_get_as_complex (argv[0], &c, &imunit))
return value_new_error (ei->pos, gnumeric_err_VALUE);
complex_tan (&res, &c);
return value_new_complex (&res, imunit);
}
/***************************************************************************/
static const char *help_imexp = {
N_("@FUNCTION=IMEXP\n"
"@SYNTAX=IMEXP(inumber)\n"
"@DESCRIPTION="
"IMEXP returns the exponential of a complex number.\n"
"This function is Excel compatible."
"\n"
"@EXAMPLES=\n"
"IMEXP(\"2-j\") equals 3.992324-6.217676j.\n"
"\n"
"@SEEALSO=IMLN")
};
int result = -1;
static Value *
gnumeric_imexp (FunctionEvalInfo *ei, Value **argv)
{
complex_t c, res;
char imunit;
/* Yes, AND is actually strict. */
Value *v = function_iterate_argument_values (ei->pos,
callback_function_and,
&result, nodes,
TRUE, TRUE);
if (v != NULL)
return v;
if (value_get_as_complex (argv[0], &c, &imunit))
/* See if there was any value worth using */
if (result == -1)
return value_new_error (ei->pos, gnumeric_err_VALUE);
complex_exp (&res, &c);
return value_new_complex (&res, imunit);
return value_new_bool (result);
}
/***************************************************************************/
static const char *help_imargument = {
N_("@FUNCTION=IMARGUMENT\n"
"@SYNTAX=IMARGUMENT(inumber)\n"
"@DESCRIPTION="
"IMARGUMENT returns the argument theta of a complex number.\n"
"This function is Excel compatible. "
"\n"
"@EXAMPLES=\n"
"IMARGUMENT(\"2-j\") equals -0.463647609.\n"
"\n"
"@SEEALSO=")
};
static Value *
gnumeric_imargument (FunctionEvalInfo *ei, Value **argv)
{
complex_t c;
char imunit;
if (value_get_as_complex (argv[0], &c, &imunit))
return value_new_error (ei->pos, gnumeric_err_VALUE);
static const char *help_not = {
N_("@FUNCTION=NOT\n"
"@SYNTAX=NOT(number)\n"
return value_new_float (complex_angle (&c));
}
/***************************************************************************/
static const char *help_imln = {
N_("@FUNCTION=IMLN\n"
"@SYNTAX=IMLN(inumber)\n"
"@DESCRIPTION="
"IMLN returns the natural logarithm of a complex number. (The "
"result will have an imaginary part between -pi and +pi. The "
"natural logarithm is not uniquely defined on complex numbers. "
"You may need to add or subtract an even multiple of pi to the "
"imaginary part.)\n"
"NOT implements the logical NOT function: the result is TRUE "
"if the @number is zero; otherwise the result is FALSE.\n"
"This function is Excel compatible. "
"\n"
"@EXAMPLES=\n"
"IMLN(\"3-j\") equals 1.15129-0.32175j.\n"
"NOT(0) equals TRUE.\n"
"NOT(TRUE) equals FALSE.\n"
"\n"
"@SEEALSO=IMEXP,IMLOG2,IMLOG10")
"@SEEALSO=AND, OR")
};
static Value *
gnumeric_imln (FunctionEvalInfo *ei, Value **argv)
gnumeric_not (FunctionEvalInfo *ei, Value **argv)
{
complex_t c, res;
char imunit;
if (value_get_as_complex (argv[0], &c, &imunit))
return value_new_error (ei->pos, gnumeric_err_VALUE);
complex_ln (&res, &c);
return value_new_complex (&res, imunit);
gboolean err, val = value_get_as_bool (argv [0], &err);
if (err)
return value_new_error (ei->pos, _("Type Mismatch"));
return value_new_bool (!val);
}
/***************************************************************************/
static const char *help_imlog2 = {
N_("@FUNCTION=IMLOG2\n"
"@SYNTAX=IMLOG2(inumber)\n"
"@DESCRIPTION="
"IMLOG2 returns the logarithm of a complex number in base 2.\n"
"This function is Excel compatible. "
"\n"
"@EXAMPLES=\n"
"IMLOG2(\"3-j\") equals 1.66096-0.46419j.\n"
"\n"
"@SEEALSO=IMLN,IMLOG10")
};
static Value *
gnumeric_imlog2 (FunctionEvalInfo *ei, Value **argv)
{
complex_t c, res;
char imunit;
if (value_get_as_complex (argv[0], &c, &imunit))
return value_new_error (ei->pos, gnumeric_err_VALUE);
complex_ln (&res, &c);
complex_scale_real (&res, 1 / M_LN2gnum);
return value_new_complex (&res, imunit);
}
/***************************************************************************/
static const char *help_or = {
N_("@FUNCTION=OR\n"
"@SYNTAX=OR(b1, b2, ...)\n"
static const char *help_imlog10 = {
N_("@FUNCTION=IMLOG10\n"
"@SYNTAX=IMLOG10(inumber)\n"
"@DESCRIPTION="
"IMLOG10 returns the logarithm of a complex number in base 10.\n"
"OR implements the logical OR function: the result is TRUE if "
"any of the values evaluated to TRUE.\n"
"@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.\n"
"If the values contain strings or empty cells those values are "
"ignored. If no logical values are provided, then the error "
"#VALUE! is returned.\n"
"This function is Excel compatible. "
"\n"
"@EXAMPLES=\n"
"IMLOG10(\"3-j\") equals 0.5-0.13973j.\n"
"\n"
"@SEEALSO=IMLN,IMLOG2")
};
static Value *
gnumeric_imlog10 (FunctionEvalInfo *ei, Value **argv)
{
complex_t c, res;
char imunit;
if (value_get_as_complex (argv[0], &c, &imunit))
return value_new_error (ei->pos, gnumeric_err_VALUE);
complex_ln (&res, &c);
complex_scale_real (&res, 1 / M_LN10gnum);
return value_new_complex (&res, imunit);
}
/***************************************************************************/
static const char *help_impower = {
N_("@FUNCTION=IMPOWER\n"
"@SYNTAX=IMPOWER(inumber,number)\n"
"@DESCRIPTION="
"IMPOWER returns a complex number raised to a power. @inumber is "
"the complex number to be raised to a power and @number is the "
"power to which you want to raise the complex number.\n"
"This function is Excel compatible."
"\n"
"@EXAMPLES=\n"
"IMPOWER(\"4-j\",2) equals 15-8j.\n"
"\n"
"@SEEALSO=IMSQRT")
};
static Value *
gnumeric_impower (FunctionEvalInfo *ei, Value **argv)
{
complex_t a, b, res;
char imunit;
if (value_get_as_complex (argv[0], &a, &imunit))
return value_new_error (ei->pos, gnumeric_err_VALUE);
if (value_get_as_complex (argv[1], &b, &imunit))
return value_new_error (ei->pos, gnumeric_err_VALUE);
if (complex_real_p (&a) && a.re <= 0 && !complex_real_p (&b))
return value_new_error (ei->pos, gnumeric_err_DIV0);
complex_pow (&res, &a, &b);
return value_new_complex (&res, imunit);
}
/***************************************************************************/
static const char *help_imdiv = {
N_("@FUNCTION=IMDIV\n"
"@SYNTAX=IMDIV(inumber,inumber)\n"
"@DESCRIPTION="
"IMDIV returns the quotient of two complex numbers.\n"
"This function is Excel compatible."
"\n"
"@EXAMPLES=\n"
"IMDIV(\"2-j\",\"2+j\") equals 0.6-0.8j.\n"
"\n"
"@SEEALSO=IMPRODUCT")
};
static Value *
gnumeric_imdiv (FunctionEvalInfo *ei, Value **argv)
{
complex_t a, b, res;
char imunit;
if (value_get_as_complex (argv[0], &a, &imunit))
return value_new_error (ei->pos, gnumeric_err_VALUE);
if (value_get_as_complex (argv[1], &b, &imunit))
return value_new_error (ei->pos, gnumeric_err_VALUE);
if (complex_zero_p (&b))
return value_new_error (ei->pos, gnumeric_err_DIV0);
complex_div (&res, &a, &b);
return value_new_complex (&res, imunit);
}
/***************************************************************************/
static const char *help_imsin = {
N_("@FUNCTION=IMSIN\n"
"@SYNTAX=IMSIN(inumber)\n"
"@DESCRIPTION="
"IMSIN returns the sine of a complex number.\n"
"This function is Excel compatible."
"\n"
"@EXAMPLES=\n"
"IMSIN(\"1+j\") equals 1.29846+0.63496j.\n"
"\n"
"@SEEALSO=IMCOS,IMTAN")
};
static Value *
gnumeric_imsin (FunctionEvalInfo *ei, Value **argv)
{
complex_t c, res;
char imunit;
if (value_get_as_complex (argv[0], &c, &imunit))
return value_new_error (ei->pos, gnumeric_err_VALUE);
complex_sin (&res, &c);
return value_new_complex (&res, imunit);
}
/***************************************************************************/
static const char *help_imsinh = {
N_("@FUNCTION=IMSINH\n"
"@SYNTAX=IMSINH(z)\n"
"@DESCRIPTION="
"IMSINH returns the complex hyperbolic sine of the complex "
"number z, sinh(z) = (exp(z) - exp(-z))/2.\n"
"\n"
"@EXAMPLES=\n"
"IMSINH(\"1+j\") equals 0.63496+1.29846j.\n"
"OR(TRUE,FALSE) equals TRUE.\n"
"OR(3>4,4<3) equals FALSE.\n"
"\n"
"@SEEALSO=IMCOSH,IMTANH")
"@SEEALSO=AND, NOT")
};
static Value *
gnumeric_imsinh (FunctionEvalInfo *ei, Value **argv)
callback_function_or (const EvalPos *ep, Value *value, void *closure)
{
complex_t c, res;
char imunit;
if (value_get_as_complex (argv[0], &c, &imunit))
return value_new_error (ei->pos, gnumeric_err_VALUE);
int *result = closure;
gboolean err;
gsl_complex_sinh (&c, &res);
return value_new_complex (&res, imunit);
}