Hello list, 

the last time I mentioned this bug (or misbehavior maybe?) I didn't get any 
feedback. Anyway, I hope I get some feedback now on this patch, which 
unfortunately makes complex number division more complex (;-) but fixes 
mistaken results in case of denominator overflow. Any ideas for optimizing 
this algorithm are welcome. 

You may reproduce with: 

        writeLn(cstr((-8E+231 - 1E+230*i) / (-1E+144 + 4E+199*i)));

without the patch it returns: 
-0.000000000000000E+000

but with the patch: 
-2.500000000000000E+030+2.000000000000000E+032i


Dimitris
--- rtl/inc/ucomplex.pp.orig3	2006-08-04 04:31:33.000000000 +0300
+++ rtl/inc/ucomplex.pp	2006-11-07 21:28:56.000000000 +0200
@@ -315,14 +315,34 @@
   inline;
   {$endif TEST_INLINE}
     { division : z := znum / zden }
+    { The following algorithm is used to properly handle 
+      denominator overflow:
+
+                 |  a + b(d/c)   c - a(d/c)
+                 |  ---------- + ---------- I     if |d| < |c|
+      a + b I    |  c + d(d/c)   a + d(d/c)
+      -------  = |
+      c + d I    |  b + a(c/d)   -a+ b(c/d)
+                 |  ---------- + ---------- I     if |d| >= |c|
+                 |  d + c(c/d)   d + c(c/d)
+    }
     var
-       denom : real;
+       tmp, denom : real;
     begin
-       { WARNING: denom may overflow here, spoiling the result! }
-       with zden do denom := (re * re) + (im * im);
-       { generates a fpu exception if denom=0 as for reals }
-       z.re := ((znum.re * zden.re) + (znum.im * zden.im)) / denom;
-       z.im := ((znum.im * zden.re) - (znum.re * zden.im)) / denom;
+       if ( abs(zden.re) > abs(zden.im) ) then
+       begin
+          tmp := zden.im / zden.re;
+          denom := zden.re + zden.im * tmp;
+          z.re := (znum.re + znum.im * tmp) / denom;
+          z.im := (znum.im - znum.re * tmp) / denom;
+       end
+       else
+       begin
+          tmp := zden.re / zden.im;
+          denom := zden.im + zden.re * tmp;
+          z.re := (znum.im + znum.re * tmp) / denom;
+          z.im := (-znum.re + znum.im * tmp) / denom;
+       end;
     end;
 
     operator / (znum : complex; r : real) z : complex;
_______________________________________________
fpc-devel maillist  -  [email protected]
http://lists.freepascal.org/mailman/listinfo/fpc-devel

Reply via email to