diff options
author | Mark Wielaard <mark@klomp.org> | 2003-07-18 11:00:09 +0000 |
---|---|---|
committer | Mark Wielaard <mark@klomp.org> | 2003-07-18 11:00:09 +0000 |
commit | f22a99fcfa1d9f20cad5813fc496fcb9168eecb0 (patch) | |
tree | b28659ad0e6d2982716df76ec2e5ca179638be9e | |
parent | 53c0b65b6b86d7ec8d625c528ae103fd71cd0c26 (diff) | |
download | classpath-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-- | ChangeLog | 7 | ||||
-rw-r--r-- | java/math/BigDecimal.java | 68 |
2 files changed, 43 insertions, 32 deletions
@@ -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); |