OSDN Git Service

2003-08-01 Jerry Quinn <jlquinn@optonline.net>
authormark <mark@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 1 Aug 2003 15:07:49 +0000 (15:07 +0000)
committermark <mark@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 1 Aug 2003 15:07:49 +0000 (15:07 +0000)
            Mark Wielaard  <mark@klomp.org>

       * java/math/BigDecimal (divide): Correctly handle
       ROUND_HALF_EVEN when amount is greater than 0.5.
       Simplify and optimize code.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@70049 138bc75d-0d04-0410-961f-82ee72b054a4

libjava/ChangeLog
libjava/java/math/BigDecimal.java

index 6ee557e..51dc687 100644 (file)
@@ -1,3 +1,10 @@
+2003-08-01  Jerry Quinn  <jlquinn@optonline.net>
+            Mark Wielaard  <mark@klomp.org>
+           
+       * java/math/BigDecimal (divide): Correctly handle
+       ROUND_HALF_EVEN when amount is greater than 0.5.
+       Simplify and optimize code.
+
 2003-07-31  Tom Tromey  <tromey@redhat.com>
 
        More for PR libgcj/11737:
index fc99cf1..f9965ad 100644 (file)
@@ -1,5 +1,5 @@
 /* java.math.BigDecimal -- Arbitrary precision decimals.
-   Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
+   Copyright (C) 1999, 2000, 2001, 2003 Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
 
@@ -273,7 +273,7 @@ public class BigDecimal extends Number implements Comparable
     // Ensure that pow gets a non-negative value.
     int valScale = val.scale;
     BigInteger valIntVal = val.intVal;
-    int power = newScale + 1 - (scale - val.scale);
+    int power = newScale - (scale - val.scale);
     if (power < 0)
       {
        // Effectively increase the scale of val to avoid an
@@ -285,50 +285,53 @@ public class BigDecimal extends Number implements Comparable
     BigInteger dividend = intVal.multiply (BigInteger.valueOf (10).pow (power));
     
     BigInteger parts[] = dividend.divideAndRemainder (valIntVal);
-//      System.out.println("int: " + parts[0]);
-//      System.out.println("rem: " + parts[1]);
 
-    int roundDigit = parts[0].mod (BigInteger.valueOf (10)).intValue ();
-    BigInteger unrounded = parts[0].divide (BigInteger.valueOf (10));
-
-    if (roundDigit == 0 && parts[1].signum () == 0) // no rounding necessary
+    BigInteger unrounded = parts[0];
+    if (parts[1].signum () == 0) // no remainder, no rounding necessary
       return new BigDecimal (unrounded, newScale);
 
-    int sign = unrounded.signum ();
+    if (roundingMode == ROUND_UNNECESSARY)
+      throw new ArithmeticException ("newScale is not large enough");
+
+    int sign = intVal.signum () * valIntVal.signum ();
 
-    switch (roundingMode)
+    if (roundingMode == ROUND_CEILING)
+      roundingMode = (sign > 0) ? ROUND_UP : ROUND_DOWN;
+    else if (roundingMode == ROUND_FLOOR)
+      roundingMode = (sign < 0) ? ROUND_UP : ROUND_DOWN;
+    else
       {
-      case ROUND_UNNECESSARY:
-       throw new ArithmeticException ("newScale is not large enough");
-      case ROUND_CEILING:
-       roundingMode = (sign == 1) ? ROUND_UP : ROUND_DOWN;
-       break;
-      case ROUND_FLOOR:
-       roundingMode = (sign == 1) ? ROUND_DOWN : ROUND_UP;
-       break;
-      case ROUND_HALF_UP:
-       roundingMode = (roundDigit >= 5) ? ROUND_UP : ROUND_DOWN;
-       break;
-      case ROUND_HALF_DOWN:
-       roundingMode = (roundDigit > 5) ? ROUND_UP : ROUND_DOWN;
-       break;
-      case ROUND_HALF_EVEN:
-       if (roundDigit < 5)
-         roundingMode = ROUND_DOWN;
-       else
+       // half is -1 if remainder*2 < positive intValue (*power), 0 if equal,
+       // 1 if >. This implies that the remainder to round is less than,
+       // equal to, or greater than half way to the next digit.
+       BigInteger posRemainder
+         = parts[1].signum () < 0 ? parts[1].negate() : parts[1];
+       valIntVal = valIntVal.signum () < 0 ? valIntVal.negate () : valIntVal;
+       int half = posRemainder.shiftLeft(1).compareTo(valIntVal);
+
+       switch(roundingMode)
          {
-           int rightmost = 
-             unrounded.mod (BigInteger.valueOf (10)).intValue ();
-           if (rightmost % 2 == 1) // odd, then ROUND_HALF_UP
+         case ROUND_HALF_UP:
+           roundingMode = (half < 0) ? ROUND_DOWN : ROUND_UP;
+           break;
+         case ROUND_HALF_DOWN:
+           roundingMode = (half > 0) ? ROUND_UP : ROUND_DOWN;
+           break;
+         case ROUND_HALF_EVEN:
+           if (half < 0)
+             roundingMode = ROUND_DOWN;
+           else if (half > 0)
+             roundingMode = ROUND_UP;
+           else if (unrounded.testBit(0)) // odd, then ROUND_HALF_UP
              roundingMode = ROUND_UP;
-           else // even, then ROUND_HALF_DOWN
-             roundingMode = (roundDigit > 5) ? ROUND_UP : ROUND_DOWN;
+           else                           // even, ROUND_HALF_DOWN
+             roundingMode = ROUND_DOWN;
+           break;
          }
-       break;
       }
 
     if (roundingMode == ROUND_UP)
-      return new BigDecimal (unrounded.add (BigInteger.valueOf (1)), newScale);
+      unrounded = unrounded.add (BigInteger.valueOf (sign > 0 ? 1 : -1));
 
     // roundingMode == ROUND_DOWN
     return new BigDecimal (unrounded, newScale);