You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by ah...@apache.org on 2019/12/07 02:27:45 UTC

[commons-numbers] 03/04: Fix overflow in sqrt()

This is an automated email from the ASF dual-hosted git repository.

aherbert pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-numbers.git

commit cc24bfcf91370e197d09b33c0d02edb6e633a40d
Author: Alex Herbert <ah...@apache.org>
AuthorDate: Sat Dec 7 01:44:45 2019 +0000

    Fix overflow in sqrt()
---
 .../apache/commons/numbers/complex/Complex.java    | 23 ++++++++++++++++++----
 1 file changed, 19 insertions(+), 4 deletions(-)

diff --git a/commons-numbers-complex/src/main/java/org/apache/commons/numbers/complex/Complex.java b/commons-numbers-complex/src/main/java/org/apache/commons/numbers/complex/Complex.java
index 42a88e4..aa2bc2a 100644
--- a/commons-numbers-complex/src/main/java/org/apache/commons/numbers/complex/Complex.java
+++ b/commons-numbers-complex/src/main/java/org/apache/commons/numbers/complex/Complex.java
@@ -1676,7 +1676,7 @@ public final class Complex implements Serializable  {
      * <ul>
      * <li>{@code |a| = }{@link Math#abs}(a)
      * <li>{@code |a + b i| = }{@link Complex#abs}(a + b i)
-     * <li>{@code sign(b) =  }{@link Math#copySign(double,double) copySign(1.0, b)}
+     * <li>{@code sign(b) = }{@link Math#copySign(double,double) copySign}(1.0, b)
      * </ul>
      *
      * @param real Real component.
@@ -1694,11 +1694,13 @@ public final class Complex implements Serializable  {
                 if (real == 0 && imaginary == 0) {
                     return new Complex(0, imaginary);
                 }
-                final double t = Math.sqrt((Math.abs(real) + Math.hypot(real, imaginary)) / 2);
+                final double t = Math.sqrt(average(Math.abs(real), Math.hypot(real, imaginary)));
+                // t is positive:
+                // To prevent overflow dividing by (2 * t) divide by t then by 2.
                 if (real >= 0) {
-                    return new Complex(t, imaginary / (2 * t));
+                    return new Complex(t, (imaginary / t) / 2);
                 }
-                return new Complex(Math.abs(imaginary) / (2 * t),
+                return new Complex((Math.abs(imaginary) / t) / 2,
                                    Math.copySign(1.0, imaginary) * t);
             }
             // Imaginary is nan
@@ -1718,6 +1720,19 @@ public final class Complex implements Serializable  {
     }
 
     /**
+     * Compute {@code (a + b) / 2} without overflow.
+     *
+     * @param a the a
+     * @param b the b
+     * @return the average
+     */
+    private static double average(double a, double b) {
+        return (b < a) ?
+                a + (b - a) / 2 :
+                b + (a - b) / 2;
+    }
+
+    /**
      * Compute the
      * <a href="http://mathworld.wolfram.com/Tangent.html">
      * tangent</a> of this complex number.