summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Wielaard <mark@klomp.org>2003-07-18 11:00:09 +0000
committerMark Wielaard <mark@klomp.org>2003-07-18 11:00:09 +0000
commitf22a99fcfa1d9f20cad5813fc496fcb9168eecb0 (patch)
treeb28659ad0e6d2982716df76ec2e5ca179638be9e
parent53c0b65b6b86d7ec8d625c528ae103fd71cd0c26 (diff)
downloadclasspath-f22a99fcfa1d9f20cad5813fc496fcb9168eecb0.tar.gz
2003-07-18 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 code.
-rw-r--r--ChangeLog7
-rw-r--r--java/math/BigDecimal.java68
2 files changed, 43 insertions, 32 deletions
diff --git a/ChangeLog b/ChangeLog
index 54c8179d4..38c04b42f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2003-07-18 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 code.
+
2003-07-17 Jeroen Frijters <jeroen@sumatra.nl>
* java/net/URLClassLoader.java (addURL): Moved implementation to
diff --git a/java/math/BigDecimal.java b/java/math/BigDecimal.java
index fc99cf1f7..f10a47b5a 100644
--- a/java/math/BigDecimal.java
+++ b/java/math/BigDecimal.java
@@ -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
@@ -288,47 +288,51 @@ public class BigDecimal extends Number implements Comparable
// 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);
+ if (roundingMode == ROUND_UNNECESSARY)
+ throw new ArithmeticException ("newScale is not large enough");
+
int sign = unrounded.signum ();
- switch (roundingMode)
+ if (roundingMode == ROUND_CEILING)
+ roundingMode = (sign == 1) ? ROUND_UP : ROUND_DOWN;
+ else if (roundingMode == ROUND_FLOOR)
+ roundingMode = (sign == 1) ? ROUND_DOWN : ROUND_UP;
+ 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 = sign == -1 ? parts[1].negate() : parts[1];
+ 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 == -1) ? ROUND_DOWN : ROUND_UP;
+ break;
+ case ROUND_HALF_DOWN:
+ roundingMode = (half == 1) ? ROUND_UP : ROUND_DOWN;
+ break;
+ case ROUND_HALF_EVEN:
+ if (half == -1)
+ roundingMode = ROUND_DOWN;
+ else if (half == 1)
+ 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);
+ return new BigDecimal (unrounded.add (BigInteger.valueOf
+ (sign != 0 ? sign : 1)), newScale);
// roundingMode == ROUND_DOWN
return new BigDecimal (unrounded, newScale);