Commit 2f18d7a1 by Jerry Quinn Committed by Mark Wielaard

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
parent cbd63935
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:
......
/* 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 ...@@ -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 ...@@ -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");
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
{
// 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)
{ {
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: case ROUND_HALF_UP:
roundingMode = (roundDigit >= 5) ? ROUND_UP : ROUND_DOWN; roundingMode = (half < 0) ? ROUND_DOWN : ROUND_UP;
break; break;
case ROUND_HALF_DOWN: case ROUND_HALF_DOWN:
roundingMode = (roundDigit > 5) ? ROUND_UP : ROUND_DOWN; roundingMode = (half > 0) ? ROUND_UP : ROUND_DOWN;
break; break;
case ROUND_HALF_EVEN: case ROUND_HALF_EVEN:
if (roundDigit < 5) if (half < 0)
roundingMode = ROUND_DOWN; roundingMode = ROUND_DOWN;
else else if (half > 0)
{
int rightmost =
unrounded.mod (BigInteger.valueOf (10)).intValue ();
if (rightmost % 2 == 1) // odd, then ROUND_HALF_UP
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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment