[goffice] Quad: add asin and acos.
- From: Morten Welinder <mortenw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [goffice] Quad: add asin and acos.
- Date: Tue, 17 Dec 2013 19:59:58 +0000 (UTC)
commit a5980b264e458c6251fab01bfad8b42426c9bc11
Author: Morten Welinder <terra gnome org>
Date: Tue Dec 17 14:59:41 2013 -0500
Quad: add asin and acos.
ChangeLog | 5 ++
NEWS | 2 +-
goffice/math/go-quad.c | 149 +++++++++++++++++++++++++++++++++++------------
goffice/math/go-quad.h | 10 +++-
tests/test-quad.c | 26 ++++++++
5 files changed, 151 insertions(+), 41 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 654ab94..6758a7c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
2013-12-17 Morten Welinder <terra gnome org>
+ * tests/test-quad.c (floor_tests): Test asin and acos.
+
+ * goffice/math/go-quad.c (go_quad_acos, go_quad_asin): new
+ functions.
+
* goffice/math/go-complex.c (go_complex_from_polar_pi)
(go_complex_angle_pi): Handle diagonals too.
diff --git a/NEWS b/NEWS
index beab22e..eb1cd54 100644
--- a/NEWS
+++ b/NEWS
@@ -7,7 +7,7 @@ Jean
Morten:
* Improve complex math, notably complex power.
- * Add quad precision log, atan2, hypot functions.
+ * Add quad precision log, atan2, hypot, asin, acos functions.
--------------------------------------------------------------------------
goffice 0.10.9:
diff --git a/goffice/math/go-quad.c b/goffice/math/go-quad.c
index 8e9c520..83cb823 100644
--- a/goffice/math/go-quad.c
+++ b/goffice/math/go-quad.c
@@ -773,30 +773,92 @@ SUFFIX(go_quad_log) (QUAD *res, const QUAD *a)
}
}
+void
+SUFFIX(go_quad_hypot) (QUAD *res, const QUAD *a, const QUAD *b)
+{
+ int e;
+ QUAD qa2, qb2, qn;
+
+ if (a->h == 0) {
+ res->h = SUFFIX(fabs)(b->h);
+ res->l = SUFFIX(fabs)(b->l);
+ return;
+ }
+ if (b->h == 0) {
+ res->h = SUFFIX(fabs)(a->h);
+ res->l = SUFFIX(fabs)(a->l);
+ return;
+ }
+
+ /* Scale by power of 2 to protect against over- and underflow */
+ (void)SUFFIX(frexp) (MAX (SUFFIX(fabs) (a->h), SUFFIX(fabs) (b->h)), &e);
+
+ qa2.h = SUFFIX(ldexp) (a->h, -e);
+ qa2.l = SUFFIX(ldexp) (a->l, -e);
+ SUFFIX(go_quad_mul) (&qa2, &qa2, &qa2);
+
+ qb2.h = SUFFIX(ldexp) (b->h, -e);
+ qb2.l = SUFFIX(ldexp) (b->l, -e);
+ SUFFIX(go_quad_mul) (&qb2, &qb2, &qb2);
+
+ SUFFIX(go_quad_add) (&qn, &qa2, &qb2);
+ SUFFIX(go_quad_sqrt) (&qn, &qn);
+ res->h = SUFFIX(ldexp) (qn.h, e);
+ res->l = SUFFIX(ldexp) (qn.l, e);
+}
+
+#ifdef DEFINE_COMMON
+typedef enum {
+ AGM_ARCSIN,
+ AGM_ARCCOS,
+ AGM_ARCTAN
+} AGM_Method;
+#endif
+
static void
-SUFFIX(go_quad_atan_internal) (QUAD *res, const QUAD *x)
+SUFFIX(go_quad_agm_internal) (QUAD *res, AGM_Method method, const QUAD *x)
{
- QUAD g, gp, dk[20], dpk[20], qr, qrp;
+ QUAD g, gp, dk[20], dpk[20], qr, qrp, qnum;
int n, k;
gboolean converged = FALSE;
- g_return_if_fail (SUFFIX(fabs) (x->h) <= 1);
-
/*
* This follows "An Algorithm for Computing Logarithms
* and Arctangents" by B. C. Carlson in *Mathematics of
* Computation*, Volume 26, Number 118, April 1972.
*
- * If need be we can do log, arcsin, arccos, arctanh,
- * arcsinh, and arccosh we the same code.
+ * If need be we can do log, arctanh, arcsinh, and
+ * arccosh we the same code.
*/
qrp = SUFFIX(go_quad_zero);
- dpk[0] = SUFFIX(go_quad_one);
- SUFFIX(go_quad_mul) (&gp, x, x);
- SUFFIX(go_quad_add) (&gp, &gp, &SUFFIX(go_quad_one));
- SUFFIX(go_quad_sqrt) (&gp, &gp);
+ switch (method) {
+ case AGM_ARCSIN:
+ g_return_if_fail (SUFFIX(fabs) (x->h) <= 1);
+ SUFFIX(go_quad_mul) (&dpk[0], x, x);
+ SUFFIX(go_quad_sub) (&dpk[0], &SUFFIX(go_quad_one), &dpk[0]);
+ SUFFIX(go_quad_sqrt) (&dpk[0], &dpk[0]);
+ gp = SUFFIX(go_quad_one);
+ qnum = *x;
+ break;
+ case AGM_ARCCOS:
+ g_return_if_fail (SUFFIX(fabs) (x->h) <= 1);
+ dpk[0] = *x;
+ gp = SUFFIX(go_quad_one);
+ SUFFIX(go_quad_mul) (&qnum, x, x);
+ SUFFIX(go_quad_sub) (&qnum, &SUFFIX(go_quad_one), &qnum);
+ SUFFIX(go_quad_sqrt) (&qnum, &qnum);
+ break;
+ case AGM_ARCTAN:
+ g_return_if_fail (SUFFIX(fabs) (x->h) <= 1);
+ dpk[0] = SUFFIX(go_quad_one);
+ SUFFIX(go_quad_hypot) (&gp, x, &SUFFIX(go_quad_one));
+ qnum = *x;
+ break;
+ default:
+ g_assert_not_reached ();
+ }
for (n = 1; n < (int)G_N_ELEMENTS(dk); n++) {
SUFFIX(go_quad_add) (&dk[0], &dpk[0], &gp);
@@ -815,8 +877,7 @@ SUFFIX(go_quad_atan_internal) (QUAD *res, const QUAD *x)
SUFFIX(go_quad_div) (&dk[k], &dk[k], &f);
}
- SUFFIX(go_quad_div) (&qr, x, &dk[n]);
-
+ SUFFIX(go_quad_div) (&qr, &qnum, &dk[n]);
SUFFIX(go_quad_sub) (&qrp, &qrp, &qr);
if (SUFFIX(fabs)(qrp.h) <= SUFFIX(ldexp) (SUFFIX(fabs)(qr.h), -2 * (DBL_MANT_DIG - 1))) {
converged = TRUE;
@@ -829,7 +890,7 @@ SUFFIX(go_quad_atan_internal) (QUAD *res, const QUAD *x)
}
if (!converged)
- g_warning ("go_quad_atan_internal(%.20g) failed to converge\n",
+ g_warning ("go_quad_agm_internal(%.20g) failed to converge\n",
(double)SUFFIX(go_quad_value) (x));
*res = qr;
@@ -879,13 +940,13 @@ SUFFIX(go_quad_atan2) (QUAD *res, const QUAD *y, const QUAD *x)
if (SUFFIX(fabs) (dx) >= SUFFIX(fabs) (dy)) {
SUFFIX(go_quad_div) (&qr, y, x);
- SUFFIX(go_quad_atan_internal) (res, &qr);
+ SUFFIX(go_quad_agm_internal) (res, AGM_ARCTAN, &qr);
} else {
DOUBLE f;
QUAD qa;
SUFFIX(go_quad_div) (&qr, x, y);
- SUFFIX(go_quad_atan_internal) (res, &qr);
+ SUFFIX(go_quad_agm_internal) (res, AGM_ARCTAN, &qr);
f = (qr.h >= 0) ? 0.5 : -0.5;
qa.h = f * SUFFIX(go_quad_pi).h;
@@ -923,36 +984,48 @@ SUFFIX(go_quad_atan2pi) (QUAD *res, const QUAD *y, const QUAD *x)
SUFFIX(go_quad_div) (res, res, &SUFFIX(go_quad_pi));
}
+/**
+ * go_quad_asin: (skip)
+ **/
+/**
+ * go_quad_asinl: (skip)
+ **/
void
-SUFFIX(go_quad_hypot) (QUAD *res, const QUAD *a, const QUAD *b)
+SUFFIX(go_quad_asin) (QUAD *res, const QUAD *a)
{
- int e;
- QUAD qa2, qb2, qn;
+ QUAD aa, aam1;
- if (a->h == 0) {
- res->h = SUFFIX(fabs)(b->h);
- res->l = SUFFIX(fabs)(b->l);
- return;
- }
- if (b->h == 0) {
- res->h = SUFFIX(fabs)(a->h);
- res->l = SUFFIX(fabs)(a->l);
+ aa.h = SUFFIX(fabs) (a->h);
+ aa.l = SUFFIX(fabs) (a->l);
+ SUFFIX(go_quad_sub) (&aam1, &aa, &SUFFIX(go_quad_one));
+ if (aam1.h > 0) {
+ SUFFIX(go_quad_init) (res, SUFFIX(go_nan));
return;
}
- /* Scale by power of 2 to protect against over- and underflow */
- (void)SUFFIX(frexp) (MAX (SUFFIX(fabs) (a->h), SUFFIX(fabs) (b->h)), &e);
+ SUFFIX(go_quad_agm_internal) (res, AGM_ARCSIN, a);
+}
- qa2.h = SUFFIX(ldexp) (a->h, -e);
- qa2.l = SUFFIX(ldexp) (a->l, -e);
- SUFFIX(go_quad_mul) (&qa2, &qa2, &qa2);
+/**
+ * go_quad_acos: (skip)
+ **/
+/**
+ * go_quad_acosl: (skip)
+ **/
+void
+SUFFIX(go_quad_acos) (QUAD *res, const QUAD *a)
+{
+ QUAD aa, aam1;
- qb2.h = SUFFIX(ldexp) (b->h, -e);
- qb2.l = SUFFIX(ldexp) (b->l, -e);
- SUFFIX(go_quad_mul) (&qb2, &qb2, &qb2);
+ aa.h = SUFFIX(fabs) (a->h);
+ aa.l = SUFFIX(fabs) (a->l);
+ SUFFIX(go_quad_sub) (&aam1, &aa, &SUFFIX(go_quad_one));
+ if (aam1.h > 0) {
+ SUFFIX(go_quad_init) (res, SUFFIX(go_nan));
+ return;
+ }
- SUFFIX(go_quad_add) (&qn, &qa2, &qb2);
- SUFFIX(go_quad_sqrt) (&qn, &qn);
- res->h = SUFFIX(ldexp) (qn.h, e);
- res->l = SUFFIX(ldexp) (qn.l, e);
+ SUFFIX(go_quad_agm_internal) (res, AGM_ARCCOS, &aa);
+ if (a->h < 0)
+ SUFFIX(go_quad_sub) (res, &SUFFIX(go_quad_pi), res);
}
diff --git a/goffice/math/go-quad.h b/goffice/math/go-quad.h
index e0d7cf5..8227b2a 100644
--- a/goffice/math/go-quad.h
+++ b/goffice/math/go-quad.h
@@ -27,9 +27,12 @@ void go_quad_pow (GOQuad *res, double *exp2, const GOQuad *x, const GOQuad *y);
void go_quad_exp (GOQuad *res, double *exp2, const GOQuad *a);
void go_quad_expm1 (GOQuad *res, const GOQuad *a);
void go_quad_log (GOQuad *res, const GOQuad *a);
+void go_quad_hypot (GOQuad *res, const GOQuad *a, const GOQuad *b);
+
void go_quad_atan2 (GOQuad *res, const GOQuad *y, const GOQuad *x);
void go_quad_atan2pi (GOQuad *res, const GOQuad *y, const GOQuad *x);
-void go_quad_hypot (GOQuad *res, const GOQuad *a, const GOQuad *b);
+void go_quad_asin (GOQuad *res, const GOQuad *a);
+void go_quad_acos (GOQuad *res, const GOQuad *a);
void go_quad_mul12 (GOQuad *res, double x, double y);
@@ -69,9 +72,12 @@ void go_quad_powl (GOQuadl *res, long double *exp2, const GOQuadl *x, const GOQu
void go_quad_expl (GOQuadl *res, long double *exp2, const GOQuadl *a);
void go_quad_expm1l (GOQuadl *res, const GOQuadl *a);
void go_quad_logl (GOQuadl *res, const GOQuadl *a);
+void go_quad_hypotl (GOQuadl *res, const GOQuadl *a, const GOQuadl *b);
+
void go_quad_atan2l (GOQuadl *res, const GOQuadl *y, const GOQuadl *x);
void go_quad_atan2pil (GOQuadl *res, const GOQuadl *y, const GOQuadl *x);
-void go_quad_hypotl (GOQuadl *res, const GOQuadl *a, const GOQuadl *b);
+void go_quad_asinl (GOQuadl *res, const GOQuadl *a);
+void go_quad_acosl (GOQuadl *res, const GOQuadl *a);
void go_quad_mul12l (GOQuadl *res, long double x, long double y);
diff --git a/tests/test-quad.c b/tests/test-quad.c
index e564b09..b4fe2f9 100644
--- a/tests/test-quad.c
+++ b/tests/test-quad.c
@@ -277,6 +277,31 @@ floor_tests (void)
g_assert (go_quad_value (&b) == 0.5);
}
+#undef TEST1
+
+/* ------------------------------------------------------------------------- */
+
+#define TEST1(a_) do { \
+ UNTEST1(a_,go_quad_asin,asin,"asin"); \
+ UNTEST1(a_,go_quad_acos,acos,"acos"); \
+} while (0)
+
+static void
+trig_tests (void)
+{
+ TEST1 (0);
+ TEST1 (0.25);
+ TEST1 (0.5);
+ TEST1 (0.75);
+ TEST1 (1);
+ TEST1 (-0.25);
+ TEST1 (-0.5);
+ TEST1 (-0.75);
+ TEST1 (-1);
+}
+
+#undef TEST1
+
/* ------------------------------------------------------------------------- */
static void
@@ -327,6 +352,7 @@ main (int argc, char **argv)
floor_tests ();
atan2_tests ();
hypot_tests ();
+ trig_tests ();
go_quad_end (state);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]