summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2010-06-18 15:46:00 -0700
committerRuss Cox <rsc@golang.org>2010-06-18 15:46:00 -0700
commite8bbf1946bbdf4923b0ac66bda8339f49fec7ab3 (patch)
tree856ce616828c0b3474d915b46ce5f07aba23fe51 /src
parenta4cc6162ab466f051c80ffb7ea06eb25517f365f (diff)
downloadgolang-e8bbf1946bbdf4923b0ac66bda8339f49fec7ab3.tar.gz
complex divide: match C99 implementation
R=iant, ken2, r, r2, ken3 CC=golang-dev http://codereview.appspot.com/1686044
Diffstat (limited to 'src')
-rw-r--r--src/pkg/runtime/complex.c70
1 files changed, 47 insertions, 23 deletions
diff --git a/src/pkg/runtime/complex.c b/src/pkg/runtime/complex.c
index ca6ed79ba..2240d9fb8 100644
--- a/src/pkg/runtime/complex.c
+++ b/src/pkg/runtime/complex.c
@@ -4,33 +4,57 @@
#include "runtime.h"
-// complex128div(num, den complex128) (quo complex128)
+typedef struct Complex128 Complex128;
+
void
-·complex128div(float64 numreal, float64 numimag,
- float64 denreal, float64 denimag,
- float64 quoreal, float64 quoimag)
+·complex128div(Complex128 n, Complex128 d, Complex128 q)
{
+ int32 ninf, dinf, nnan, dnan;
float64 a, b, ratio, denom;
- a = denreal;
- if(a < 0)
- a = -a;
- b = denimag;
- if(b < 0)
- b = -b;
- if(a <= b) {
- if(b == 0)
- panicstring("complex divide by zero");
- ratio = denreal/denimag;
- denom = denreal*ratio + denimag;
- quoreal = (numreal*ratio + numimag) / denom;
- quoimag = (numimag*ratio - numreal) / denom;
+ // Special cases as in C99.
+ ninf = isInf(n.real, 0) || isInf(n.imag, 0);
+ dinf = isInf(d.real, 0) || isInf(d.imag, 0);
+
+ nnan = !ninf && (isNaN(n.real) || isNaN(n.imag));
+ dnan = !dinf && (isNaN(d.real) || isNaN(d.imag));
+
+ if(nnan || dnan) {
+ q.real = NaN();
+ q.imag = NaN();
+ } else if(ninf && !dinf && !dnan) {
+ q.real = Inf(0);
+ q.imag = Inf(0);
+ } else if(!ninf && !nnan && dinf) {
+ q.real = 0;
+ q.imag = 0;
+ } else if(d.real == 0 && d.imag == 0) {
+ if(n.real == 0 && n.imag == 0) {
+ q.real = NaN();
+ q.imag = NaN();
+ } else {
+ q.real = Inf(0);
+ q.imag = Inf(0);
+ }
} else {
- ratio = denimag/denreal;
- denom = denimag*ratio + denreal;
- quoreal = (numimag*ratio + numreal) / denom;
- quoimag = (numimag - numreal*ratio) / denom;
+ // Standard complex arithmetic, factored to avoid unnecessary overflow.
+ a = d.real;
+ if(a < 0)
+ a = -a;
+ b = d.imag;
+ if(b < 0)
+ b = -b;
+ if(a <= b) {
+ ratio = d.real/d.imag;
+ denom = d.real*ratio + d.imag;
+ q.real = (n.real*ratio + n.imag) / denom;
+ q.imag = (n.imag*ratio - n.real) / denom;
+ } else {
+ ratio = d.imag/d.real;
+ denom = d.imag*ratio + d.real;
+ q.real = (n.imag*ratio + n.real) / denom;
+ q.imag = (n.imag - n.real*ratio) / denom;
+ }
}
- FLUSH(&quoreal);
- FLUSH(&quoimag);
+ FLUSH(&q);
}