BigDecimal (divide): Correctly handle ROUND_HALF_EVEN when amount is greater than 0.5.

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.

Co-Authored-By: Mark Wielaard <mark@klomp.org>

From-SVN: r70049
This commit is contained in:
Jerry Quinn 2003-08-01 15:07:49 +00:00 committed by Mark Wielaard
parent cbd63935d8
commit 2f18d7a1a8
2 changed files with 45 additions and 35 deletions

View 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> 2003-07-31 Tom Tromey <tromey@redhat.com>
More for PR libgcj/11737: More for PR libgcj/11737:

View file

@ -1,5 +1,5 @@
/* java.math.BigDecimal -- Arbitrary precision decimals. /* 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. 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. // Ensure that pow gets a non-negative value.
int valScale = val.scale; int valScale = val.scale;
BigInteger valIntVal = val.intVal; BigInteger valIntVal = val.intVal;
int power = newScale + 1 - (scale - val.scale); int power = newScale - (scale - val.scale);
if (power < 0) if (power < 0)
{ {
// Effectively increase the scale of val to avoid an // 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 dividend = intVal.multiply (BigInteger.valueOf (10).pow (power));
BigInteger parts[] = dividend.divideAndRemainder (valIntVal); 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];
BigInteger unrounded = parts[0].divide (BigInteger.valueOf (10)); if (parts[1].signum () == 0) // no remainder, no rounding necessary
if (roundDigit == 0 && parts[1].signum () == 0) // no rounding necessary
return new BigDecimal (unrounded, newScale); return new BigDecimal (unrounded, newScale);
int sign = unrounded.signum (); if (roundingMode == ROUND_UNNECESSARY)
throw new ArithmeticException ("newScale is not large enough");
switch (roundingMode) int sign = intVal.signum () * valIntVal.signum ();
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: // half is -1 if remainder*2 < positive intValue (*power), 0 if equal,
throw new ArithmeticException ("newScale is not large enough"); // 1 if >. This implies that the remainder to round is less than,
case ROUND_CEILING: // equal to, or greater than half way to the next digit.
roundingMode = (sign == 1) ? ROUND_UP : ROUND_DOWN; BigInteger posRemainder
break; = parts[1].signum () < 0 ? parts[1].negate() : parts[1];
case ROUND_FLOOR: valIntVal = valIntVal.signum () < 0 ? valIntVal.negate () : valIntVal;
roundingMode = (sign == 1) ? ROUND_DOWN : ROUND_UP; int half = posRemainder.shiftLeft(1).compareTo(valIntVal);
break;
case ROUND_HALF_UP: switch(roundingMode)
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
{ {
int rightmost = case ROUND_HALF_UP:
unrounded.mod (BigInteger.valueOf (10)).intValue (); roundingMode = (half < 0) ? ROUND_DOWN : ROUND_UP;
if (rightmost % 2 == 1) // odd, then ROUND_HALF_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; roundingMode = ROUND_UP;
else // even, then ROUND_HALF_DOWN else if (unrounded.testBit(0)) // odd, then ROUND_HALF_UP
roundingMode = (roundDigit > 5) ? ROUND_UP : ROUND_DOWN; roundingMode = ROUND_UP;
else // even, ROUND_HALF_DOWN
roundingMode = ROUND_DOWN;
break;
} }
break;
} }
if (roundingMode == ROUND_UP) 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 // roundingMode == ROUND_DOWN
return new BigDecimal (unrounded, newScale); return new BigDecimal (unrounded, newScale);