division of complex numbers

Daniel Gildea <[email protected]> Fri, 23 May 2025 12:44:59 -0400
Newsgroups gmane.lisp.gcl.devel
Message-ID <[email protected]>
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);
 	}