[goffice] Complex: handle extreme arguments better.
- From: Morten Welinder <mortenw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [goffice] Complex: handle extreme arguments better.
- Date: Thu, 24 Mar 2016 15:30:46 +0000 (UTC)
commit 2bd6408b294c6b09f8ec814368cda62f3892a148
Author: Morten Welinder <terra gnome org>
Date: Thu Mar 24 11:30:23 2016 -0400
Complex: handle extreme arguments better.
ChangeLog | 7 ++++
NEWS | 4 ++
goffice/math/go-complex.c | 79 +++++++++++++++++++++++++++++++++++----------
3 files changed, 73 insertions(+), 17 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 37fbffb..b907ef4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2016-03-24 Morten Welinder <terra gnome org>
+
+ * goffice/math/go-complex.c (go_complex_sqrt): Avoid extreme-case
+ unnecessary overflow.
+ (go_complex_div): Avoid extreme-case unnecessary overflow and
+ marginally improve accuracy.
+
2016-03-22 Morten Welinder <terra gnome org>
* configure.ac: Post-release bump.
diff --git a/NEWS b/NEWS
index 74e004a..a6a4de8 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,9 @@
goffice 0.10.29:
+Morten:
+ * Improve go_complex_sqrt.
+ * Improve go_complex_div.
+
--------------------------------------------------------------------------
goffice 0.10.28:
diff --git a/goffice/math/go-complex.c b/goffice/math/go-complex.c
index 32608ea..6375f11 100644
--- a/goffice/math/go-complex.c
+++ b/goffice/math/go-complex.c
@@ -247,23 +247,58 @@ SUFFIX(go_complex_mul) (COMPLEX *dst, COMPLEX const *a, COMPLEX const *b)
void
SUFFIX(go_complex_div) (COMPLEX *dst, COMPLEX const *a, COMPLEX const *b)
{
- DOUBLE bmod = SUFFIX(go_complex_mod) (b);
-
- if (bmod >= GO_const(1e10) || bmod < GO_const(1e-10)) {
- /* Ok, it's very big or very small. */
- DOUBLE a_re = a->re / bmod;
- DOUBLE a_im = a->im / bmod;
- DOUBLE b_re = b->re / bmod;
- DOUBLE b_im = b->im / bmod;
- SUFFIX(go_complex_init) (dst,
- a_re * b_re + a_im * b_im,
- a_im * b_re - a_re * b_im);
- } else {
- DOUBLE bmodsqr = bmod * bmod;
- SUFFIX(go_complex_init) (dst,
- (a->re * b->re + a->im * b->im) / bmodsqr,
- (a->im * b->re - a->re * b->im) / bmodsqr);
+ DOUBLE a_re = a->re, a_im = a->im;
+ DOUBLE b_re = b->re, b_im = b->im;
+ DOUBLE asize = MAX (SUFFIX(fabs)(a_re), SUFFIX(fabs)(a_im));
+ DOUBLE bsize = MAX (SUFFIX(fabs)(b_re), SUFFIX(fabs)(b_im));
+ DOUBLE bmodsqr, q_re, q_im;
+ int e = 0;
+
+ if (!SUFFIX(go_finite) (asize) || !SUFFIX(go_finite) (bsize) ||
+ bsize == 0) {
+ // Inf or Nan occurs somewhere. Or divide by zero.
+ SUFFIX(go_complex_invalid) (dst);
+ return;
+ }
+
+ if (b_im == 0) {
+ // Special case for correctly-rounded result
+ SUFFIX(go_complex_init) (dst, a_re / b_re, a_im / b_re);
+ return;
+ }
+
+ if (b_re == 0) {
+ // Special case for correctly-rounded result
+ SUFFIX(go_complex_init) (dst, a_im / b_im, -a_re / b_im);
+ return;
+ }
+
+ if (asize + bsize > 1e100 || asize < 1e-100 || bsize < 1e-100) {
+ // Avoid overflows and underflows by scaling both arguments
+ // to sane sizes without any rounding errors.
+ int ea, eb;
+
+ (void)SUFFIX(frexp) (asize, &ea);
+ a_re = SUFFIX(ldexp) (a_re, -ea);
+ a_im = SUFFIX(ldexp) (a_im, -ea);
+
+ (void)SUFFIX(frexp) (bsize, &eb);
+ b_re = SUFFIX(ldexp) (b_re, -eb);
+ b_im = SUFFIX(ldexp) (b_im, -eb);
+
+ e = ea - eb;
}
+
+ bmodsqr = b_re * b_re + b_im * b_im;
+ q_re = (a_re * b_re + a_im * b_im) / bmodsqr;
+ q_im = (a_im * b_re - a_re * b_im) / bmodsqr;
+
+ if (e) {
+ q_re = SUFFIX(ldexp) (q_re, e);
+ q_im = SUFFIX(ldexp) (q_im, e);
+ }
+
+ SUFFIX(go_complex_init) (dst, q_re, q_im);
}
/* ------------------------------------------------------------------------- */
@@ -271,6 +306,8 @@ SUFFIX(go_complex_div) (COMPLEX *dst, COMPLEX const *a, COMPLEX const *b)
void
SUFFIX(go_complex_sqrt) (COMPLEX *dst, COMPLEX const *src)
{
+ DOUBLE m, sm;
+
if (src->re < 0 && -src->re > SUFFIX(fabs)(src->im)) {
// Near the negative axis we do not want to squeeze
// angle/pi against +-1.
@@ -285,9 +322,17 @@ SUFFIX(go_complex_sqrt) (COMPLEX *dst, COMPLEX const *src)
return;
}
+ m = SUFFIX(go_complex_mod) (src);
+ if (SUFFIX(go_finite) (m))
+ sm = SUFFIX(sqrt) (m);
+ else {
+ // Overflow avoidance
+ sm = 2 * SUFFIX(sqrt) (SUFFIX(hypot) (src->re / 4, src->im / 4));
+ }
+
SUFFIX(go_complex_from_polar_pi)
(dst,
- SUFFIX(sqrt) (SUFFIX(go_complex_mod) (src)),
+ sm,
SUFFIX(go_complex_angle_pi) (src) / 2);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]