[gnumeric] INFACT, IMGAMMA: New functions.
- From: Morten Welinder <mortenw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnumeric] INFACT, IMGAMMA: New functions.
- Date: Tue, 3 Dec 2013 04:08:56 +0000 (UTC)
commit f0a7d3ae3d98b6ddb0e519649f8e9feffe6d9a87
Author: Morten Welinder <terra gnome org>
Date: Mon Dec 2 23:06:55 2013 -0500
INFACT, IMGAMMA: New functions.
Because we can. And because the complex gamma functions plays
a part in the complex incomplete gamma function which, in turn,
plays a part in bessel function series.
NEWS | 1 +
plugins/fn-complex/functions.c | 58 +++++++++++++++++++++++++
plugins/fn-complex/plugin.xml.in | 2 +
src/complex.c | 88 ++++++++++++++++++++++++++++++++++++++
src/complex.h | 3 +
5 files changed, 152 insertions(+), 0 deletions(-)
---
diff --git a/NEWS b/NEWS
index 0b9eff5..00ff9c8 100644
--- a/NEWS
+++ b/NEWS
@@ -7,6 +7,7 @@ Morten:
* Extend POCHHAMMER to negative values.
* Improve accuracy of BETA and BETALN.
* Improve accuracy of BESSELJ and BESSELY.
+ * New functions: IMGAMMA, IMFACT.
--------------------------------------------------------------------------
Gnumeric 1.12.9
diff --git a/plugins/fn-complex/functions.c b/plugins/fn-complex/functions.c
index 8da2f45..93373a1 100644
--- a/plugins/fn-complex/functions.c
+++ b/plugins/fn-complex/functions.c
@@ -1094,6 +1094,56 @@ gnumeric_imsqrt (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
/***************************************************************************/
+static GnmFuncHelp const help_imfact[] = {
+ { GNM_FUNC_HELP_NAME, F_("IMFACT:the factorial of the complex number @{z}") },
+ { GNM_FUNC_HELP_ARG, F_("z:a complex number") },
+ { GNM_FUNC_HELP_NOTE, F_("If @{z} is not a valid complex number, #VALUE! is returned.") },
+ { GNM_FUNC_HELP_EXAMPLES, "=IMFACT(\"1+j\")" },
+ { GNM_FUNC_HELP_SEEALSO, "IMGAMMA" },
+ { GNM_FUNC_HELP_END}
+};
+
+
+static GnmValue *
+gnumeric_imfact (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
+{
+ complex_t c, res;
+ char imunit;
+
+ if (value_get_as_complex (argv[0], &c, &imunit))
+ return value_new_error_NUM (ei->pos);
+
+ complex_fact (&res, &c);
+ return value_new_complex (&res, imunit);
+}
+
+/***************************************************************************/
+
+static GnmFuncHelp const help_imgamma[] = {
+ { GNM_FUNC_HELP_NAME, F_("IMGAMMA:the gamma function of the complex number @{z}") },
+ { GNM_FUNC_HELP_ARG, F_("z:a complex number") },
+ { GNM_FUNC_HELP_NOTE, F_("If @{z} is not a valid complex number, #VALUE! is returned.") },
+ { GNM_FUNC_HELP_EXAMPLES, "=IMGAMMA(\"1+j\")" },
+ { GNM_FUNC_HELP_SEEALSO, "IMGAMMA" },
+ { GNM_FUNC_HELP_END}
+};
+
+
+static GnmValue *
+gnumeric_imgamma (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
+{
+ complex_t c, res;
+ char imunit;
+
+ if (value_get_as_complex (argv[0], &c, &imunit))
+ return value_new_error_NUM (ei->pos);
+
+ complex_gamma (&res, &c);
+ return value_new_complex (&res, imunit);
+}
+
+/***************************************************************************/
+
static GnmFuncHelp const help_imsub[] = {
{ GNM_FUNC_HELP_NAME, F_("IMSUB:the difference of two complex numbers") },
{ GNM_FUNC_HELP_ARG, F_("z1:a complex number") },
@@ -1355,5 +1405,13 @@ GnmFuncDescriptor const complex_functions[] = {
{ "imarccoth", "S", help_imarccoth,
gnumeric_imarccoth, NULL, NULL, NULL,
GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
+
+ { "imfact", "S", help_imfact,
+ gnumeric_imfact, NULL, NULL, NULL,
+ GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC, GNM_FUNC_TEST_STATUS_NO_TESTSUITE },
+ { "imgamma", "S", help_imgamma,
+ gnumeric_imgamma, NULL, NULL, NULL,
+ GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC, GNM_FUNC_TEST_STATUS_NO_TESTSUITE },
+
{NULL}
};
diff --git a/plugins/fn-complex/plugin.xml.in b/plugins/fn-complex/plugin.xml.in
index 094b034..7d7b7e2 100644
--- a/plugins/fn-complex/plugin.xml.in
+++ b/plugins/fn-complex/plugin.xml.in
@@ -16,6 +16,8 @@
<function name="imaginary"/>
<function name="imargument"/>
<function name="imconjugate"/>
+ <function name="imfact"/>
+ <function name="imgamma"/>
<function name="iminv"/>
<function name="imneg"/>
<function name="imcos"/>
diff --git a/src/complex.c b/src/complex.c
index 739324e..fd707ce 100644
--- a/src/complex.c
+++ b/src/complex.c
@@ -14,6 +14,7 @@
#include <stdlib.h>
#include <errno.h>
#include <mathfunc.h>
+#include <sf-gamma.h>
/* ------------------------------------------------------------------------- */
@@ -177,3 +178,90 @@ complex_invalid_p (complex_t const *src)
}
/* ------------------------------------------------------------------------- */
+
+void
+complex_gamma (complex_t *dst, complex_t const *src)
+{
+ if (complex_real_p (src)) {
+ complex_init (dst, gnm_gamma (src->re), 0);
+ } else {
+ complex_t z = *src, f;
+
+ complex_fact (&f, src);
+ complex_div (dst, &f, &z);
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+void
+complex_fact (complex_t *dst, complex_t const *src)
+{
+ if (complex_real_p (src)) {
+ complex_init (dst, gnm_fact (src->re), 0);
+ } else if (src->re < 0.5) {
+ /* Fact(z) = -pi / (sin(pi*z) * Gamma(-z)) */
+ complex_t a, b, mz;
+
+ complex_init (&mz, -src->re, -src->im);
+ complex_gamma (&a, &mz);
+
+ complex_init (&b,
+ M_PIgnum * gnm_fmod (src->re, 2),
+ M_PIgnum * src->im);
+ complex_sin (&b, &b);
+
+ complex_mul (&a, &a, &b);
+
+ complex_init (&b, -M_PIgnum, 0);
+
+ complex_div (dst, &b, &a);
+ } else {
+ static const gnm_float c[] = {
+ GNM_const (0.99999999999999709182),
+ GNM_const (57.156235665862923517),
+ GNM_const (-59.597960355475491248),
+ GNM_const (14.136097974741747174),
+ GNM_const (-0.49191381609762019978),
+ GNM_const (0.33994649984811888699e-4),
+ GNM_const (0.46523628927048575665e-4),
+ GNM_const (-0.98374475304879564677e-4),
+ GNM_const (0.15808870322491248884e-3),
+ GNM_const (-0.21026444172410488319e-3),
+ GNM_const (0.21743961811521264320e-3),
+ GNM_const (-0.16431810653676389022e-3),
+ GNM_const (0.84418223983852743293e-4),
+ GNM_const (-0.26190838401581408670e-4),
+ GNM_const (0.36899182659531622704e-5)
+ };
+ const gnm_float g = GNM_const(607.0) / 128;
+ const gnm_const sqrt2pi =
+ gnm_const (2.506628274631000502415765284811045253006986740609938316629923);
+ complex_t zph, zpgh, s, f;
+ int i;
+
+ complex_init (&zph, src->re + 0.5, src->im);
+ complex_init (&zpgh, src->re + g + 0.5, src->im);
+ complex_init (&s, 0, 0);
+
+ for (i = G_N_ELEMENTS(c) - 1; i >= 1; i--) {
+ complex_t d, q;
+ complex_init (&d, src->re + i, src->im);
+ complex_init (&q, c[i], 0);
+ complex_div (&q, &q, &d);
+ complex_add (&s, &s, &q);
+ }
+ s.re += c[0];
+
+ complex_init (&f, sqrt2pi, 0);
+ complex_mul (&s, &s, &f);
+ complex_exp (&f, &zpgh);
+ complex_div (&s, &s, &f);
+ complex_pow (&f, &zpgh, &zph);
+ complex_mul (&s, &s, &f);
+
+ *dst = s;
+ }
+}
+
+/* ------------------------------------------------------------------------- */
diff --git a/src/complex.h b/src/complex.h
index 7efafc4..f06dea4 100644
--- a/src/complex.h
+++ b/src/complex.h
@@ -66,6 +66,9 @@ int complex_from_string (complex_t *dst, char const *src, char *imunit);
int complex_invalid_p (complex_t const *src);
+void complex_gamma (complex_t *dst, complex_t const *src);
+void complex_fact (complex_t *dst, complex_t const *src);
+
/* ------------------------------------------------------------------------- */
G_END_DECLS
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]