Here is a patch with a more precision-aware implementation of
division of complex numbers. I based this code on the implementation
in sbcl. This patch fixes an error in the maxima test suite:
Running tests in rtest_elliptic:
***************** rtest_elliptic.mac: Problem 232 (line 1071)
*****************
Input:
closeto(jacobi_am(1.5, 1.5 + %i) - (0.9340542168700783
- 0.3723960452146072 %i),
5.4673E-16)
Result:
1.0990647210786426E-15
This differed from the expected result:
true
diff --git a/gcl/o/num_arith.c b/gcl/o/num_arith.c
index a31743cba..fdc7b4b38 100644
--- a/gcl/o/num_arith.c
+++ b/gcl/o/num_arith.c
@@ -1006,18 +1006,32 @@ number_divide(object x, object y)
x = number_to_complex(x);
y = number_to_complex(y);
- z1 = number_times(y->cmp.cmp_real, y->cmp.cmp_real);
- z2 = number_times(y->cmp.cmp_imag, y->cmp.cmp_imag);
- z3 = number_plus(z1, z2);
- /* if (number_zerop(z3 = number_plus(z1, z2)))
DIVISION_BY_ZERO(sLD,list(2,x,y)); */
- z1 = number_times(x->cmp.cmp_real, y->cmp.cmp_real);
- z2 = number_times(x->cmp.cmp_imag, y->cmp.cmp_imag);
- z1 = number_plus(z1, z2);
- z = number_times(x->cmp.cmp_imag, y->cmp.cmp_real);
- z2 = number_times(x->cmp.cmp_real, y->cmp.cmp_imag);
- z2 = number_minus(z, z2);
- z1 = number_divide(z1, z3);
- z2 = number_divide(z2, z3);
+ if ( 1 == number_compare(number_abs(y->cmp.cmp_real),
+ number_abs(y->cmp.cmp_imag)) ) {
+ object r = number_divide(y->cmp.cmp_imag, y->cmp.cmp_real);
+ object dn = number_plus(y->cmp.cmp_real,
+ number_times(r, y->cmp.cmp_imag));
+ z1 = number_divide(number_plus(x->cmp.cmp_real,
+ number_times(x->cmp.cmp_imag,
+ r)),
+ dn);
+ z2 = number_divide(number_minus(x->cmp.cmp_imag,
+ number_times(x->cmp.cmp_real,
+ r)),
+ dn);
+ } else {
+ object r = number_divide(y->cmp.cmp_real, y->cmp.cmp_imag);
+ object dn = number_plus(y->cmp.cmp_imag,
+ number_times(r, y->cmp.cmp_real));
+ z1 = number_divide(number_plus(number_times(x->cmp.cmp_real,
+ r),
+ x->cmp.cmp_imag),
+ dn);
+ z2 = number_divide(number_minus(number_times(x->cmp.cmp_imag,
+ r),
+ x->cmp.cmp_real),
+ dn);
+ }
z = make_complex(z1, z2);
return(z);
}