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)
switch (roundingMode)
{
case ROUND_UNNECESSARY:
throw new ArithmeticException ("newScale is not large enough"); throw new ArithmeticException ("newScale is not large enough");
case ROUND_CEILING:
roundingMode = (sign == 1) ? ROUND_UP : ROUND_DOWN; int sign = intVal.signum () * valIntVal.signum ();
break;
case ROUND_FLOOR: if (roundingMode == ROUND_CEILING)
roundingMode = (sign == 1) ? ROUND_DOWN : ROUND_UP; roundingMode = (sign > 0) ? ROUND_UP : ROUND_DOWN;
break; else if (roundingMode == ROUND_FLOOR)
case ROUND_HALF_UP: roundingMode = (sign < 0) ? ROUND_UP : ROUND_DOWN;
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 else
{ {
int rightmost = // half is -1 if remainder*2 < positive intValue (*power), 0 if equal,
unrounded.mod (BigInteger.valueOf (10)).intValue (); // 1 if >. This implies that the remainder to round is less than,
if (rightmost % 2 == 1) // odd, then ROUND_HALF_UP // equal to, or greater than half way to the next digit.
roundingMode = ROUND_UP; BigInteger posRemainder
else // even, then ROUND_HALF_DOWN = parts[1].signum () < 0 ? parts[1].negate() : parts[1];
roundingMode = (roundDigit > 5) ? ROUND_UP : ROUND_DOWN; valIntVal = valIntVal.signum () < 0 ? valIntVal.negate () : valIntVal;
} int half = posRemainder.shiftLeft(1).compareTo(valIntVal);
switch(roundingMode)
{
case ROUND_HALF_UP:
roundingMode = (half < 0) ? ROUND_DOWN : ROUND_UP;
break; 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, ROUND_HALF_DOWN
roundingMode = ROUND_DOWN;
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);