You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by er...@apache.org on 2019/07/01 17:25:00 UTC

[commons-numbers] 06/07: NUMBERS-127: Fraction(int, int): Negate numerator and denominator only after reduction to lowest terms

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

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

commit ac1b27356853d98acfab98db2b9f535325adacf8
Author: Schamschi <he...@gmx.at>
AuthorDate: Mon Jul 1 14:57:58 2019 +0200

    NUMBERS-127: Fraction(int, int): Negate numerator and denominator only after reduction to lowest terms
---
 .../apache/commons/numbers/fraction/Fraction.java  | 24 ++++++++++++++--------
 .../commons/numbers/fraction/CommonTestCases.java  |  3 +++
 2 files changed, 19 insertions(+), 8 deletions(-)

diff --git a/commons-numbers-fraction/src/main/java/org/apache/commons/numbers/fraction/Fraction.java b/commons-numbers-fraction/src/main/java/org/apache/commons/numbers/fraction/Fraction.java
index d8dbea4..9920d03 100644
--- a/commons-numbers-fraction/src/main/java/org/apache/commons/numbers/fraction/Fraction.java
+++ b/commons-numbers-fraction/src/main/java/org/apache/commons/numbers/fraction/Fraction.java
@@ -162,15 +162,18 @@ public class Fraction
         if (den == 0) {
             throw new ArithmeticException("division by zero");
         }
-        if (den < 0) {
-            if (num == Integer.MIN_VALUE ||
-                den == Integer.MIN_VALUE) {
-                throw new FractionException(FractionException.ERROR_NEGATION_OVERFLOW, num, den);
-            }
-            num = -num;
-            den = -den;
+
+        /*
+         * if num and den are both 2^-31, or if one is 0 and the other is 2^-31,
+         * the calculation of the gcd below will fail. Ensure that this does not
+         * happen by dividing both by 2 in case both are even.
+         */
+        if (((num | den) & 1) == 0) {
+            num >>= 1;
+            den >>= 1;
         }
-        // reduce numerator and denominator by greatest common denominator.
+
+        // reduce numerator and denominator by greatest common divisor.
         final int d = ArithmeticUtils.gcd(num, den);
         if (d > 1) {
             num /= d;
@@ -179,9 +182,14 @@ public class Fraction
 
         // move sign to numerator.
         if (den < 0) {
+            if (num == Integer.MIN_VALUE ||
+                den == Integer.MIN_VALUE) {
+                throw new FractionException(FractionException.ERROR_NEGATION_OVERFLOW, num, den);
+            }
             num = -num;
             den = -den;
         }
+
         this.numerator   = num;
         this.denominator = den;
     }
diff --git a/commons-numbers-fraction/src/test/java/org/apache/commons/numbers/fraction/CommonTestCases.java b/commons-numbers-fraction/src/test/java/org/apache/commons/numbers/fraction/CommonTestCases.java
index 3b71c72..d28ef63 100644
--- a/commons-numbers-fraction/src/test/java/org/apache/commons/numbers/fraction/CommonTestCases.java
+++ b/commons-numbers-fraction/src/test/java/org/apache/commons/numbers/fraction/CommonTestCases.java
@@ -86,6 +86,9 @@ class CommonTestCases {
         testCases.add(new UnaryOperatorTestCase(-2, 4, -1, 2));
         testCases.add(new UnaryOperatorTestCase(2, -4, -1, 2));
 
+        testCases.add(new UnaryOperatorTestCase(2, Integer.MIN_VALUE, -1, - (Integer.MIN_VALUE / 2)));
+        testCases.add(new UnaryOperatorTestCase(Integer.MIN_VALUE, -2, - (Integer.MIN_VALUE / 2), 1));
+
         return testCases;
     }