Source for java.math.BigDecimal

   1: /* java.math.BigDecimal -- Arbitrary precision decimals.
   2:    Copyright (C) 1999, 2000, 2001, 2003 Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10:  
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: package java.math;
  39: 
  40: public class BigDecimal extends Number implements Comparable
  41: {
  42:   private BigInteger intVal;
  43:   private int scale;
  44:   private static final long serialVersionUID = 6108874887143696463L;
  45: 
  46:   private static final BigDecimal ZERO = 
  47:     new BigDecimal (BigInteger.valueOf (0), 0);
  48: 
  49:   private static final BigDecimal ONE = 
  50:     new BigDecimal (BigInteger.valueOf (1), 0);
  51: 
  52:   public static final int ROUND_UP = 0;
  53:   public static final int ROUND_DOWN = 1;
  54:   public static final int ROUND_CEILING = 2;
  55:   public static final int ROUND_FLOOR = 3;
  56:   public static final int ROUND_HALF_UP = 4;
  57:   public static final int ROUND_HALF_DOWN = 5;
  58:   public static final int ROUND_HALF_EVEN = 6;
  59:   public static final int ROUND_UNNECESSARY = 7;
  60: 
  61:   public BigDecimal (BigInteger num) 
  62:   {
  63:     this (num, 0);
  64:   }
  65: 
  66:   public BigDecimal (BigInteger num, int scale) throws NumberFormatException 
  67:   {
  68:     if (scale < 0) 
  69:       throw new NumberFormatException ("scale of " + scale + " is < 0");
  70:     this.intVal = num;
  71:     this.scale = scale;
  72:   }
  73: 
  74:   public BigDecimal (double num) throws NumberFormatException 
  75:   {
  76:     if (Double.isInfinite (num) || Double.isNaN (num))
  77:       throw new NumberFormatException ("invalid argument: " + num);
  78:     // Note we can't convert NUM to a String and then use the
  79:     // String-based constructor.  The BigDecimal documentation makes
  80:     // it clear that the two constructors work differently.
  81: 
  82:     final int mantissaBits = 52;
  83:     final int exponentBits = 11;
  84:     final long mantMask = (1L << mantissaBits) - 1;
  85:     final long expMask = (1L << exponentBits) - 1;
  86: 
  87:     long bits = Double.doubleToLongBits (num);
  88:     long mantissa = bits & mantMask;
  89:     long exponent = (bits >>> mantissaBits) & expMask;
  90:     boolean denormal = exponent == 0;
  91:     // Correct the exponent for the bias.
  92:     exponent -= denormal ? 1022 : 1023;
  93:     // Now correct the exponent to account for the bits to the right
  94:     // of the decimal.
  95:     exponent -= mantissaBits;
  96:     // Ordinary numbers have an implied leading `1' bit.
  97:     if (! denormal)
  98:       mantissa |= (1L << mantissaBits);
  99: 
 100:     // Shave off factors of 10.
 101:     while (exponent < 0 && (mantissa & 1) == 0)
 102:       {
 103:     ++exponent;
 104:     mantissa >>= 1;
 105:       }
 106: 
 107:     intVal = BigInteger.valueOf (bits < 0 ? - mantissa : mantissa);
 108:     if (exponent < 0)
 109:       {
 110:     // We have MANTISSA * 2 ^ (EXPONENT).
 111:     // Since (1/2)^N == 5^N * 10^-N we can easily convert this
 112:     // into a power of 10.
 113:     scale = (int) (- exponent);
 114:     BigInteger mult = BigInteger.valueOf (5).pow (scale);
 115:     intVal = intVal.multiply (mult);
 116:       }
 117:     else
 118:       {
 119:     intVal = intVal.shiftLeft ((int) exponent);
 120:     scale = 0;
 121:       }
 122:   }
 123: 
 124:   public BigDecimal (String num) throws NumberFormatException 
 125:   {
 126:     int len = num.length();
 127:     int start = 0, point = 0;
 128:     int dot = -1;
 129:     boolean negative = false;
 130:     if (num.charAt(0) == '+')
 131:       {
 132:     ++start;
 133:     ++point;
 134:       }
 135:     else if (num.charAt(0) == '-')
 136:       {
 137:     ++start;
 138:     ++point;
 139:     negative = true;
 140:       }
 141: 
 142:     while (point < len)
 143:       {
 144:     char c = num.charAt (point);
 145:     if (c == '.')
 146:       {
 147:         if (dot >= 0)
 148:           throw new NumberFormatException ("multiple `.'s in number");
 149:         dot = point;
 150:       }
 151:     else if (c == 'e' || c == 'E')
 152:       break;
 153:     else if (Character.digit (c, 10) < 0)
 154:       throw new NumberFormatException ("unrecognized character: " + c);
 155:     ++point;
 156:       }
 157: 
 158:     String val;
 159:     if (dot >= 0)
 160:       {
 161:     val = num.substring (start, dot) + num.substring (dot + 1, point);
 162:     scale = point - 1 - dot;
 163:       }
 164:     else
 165:       {
 166:     val = num.substring (start, point);
 167:     scale = 0;
 168:       }
 169:     if (val.length () == 0)
 170:       throw new NumberFormatException ("no digits seen");
 171: 
 172:     if (negative)
 173:       val = "-" + val;
 174:     intVal = new BigInteger (val);
 175: 
 176:     // Now parse exponent.
 177:     if (point < len)
 178:       {
 179:         point++;
 180:         if (num.charAt(point) == '+')
 181:           point++;
 182: 
 183:         if (point >= len )
 184:           throw new NumberFormatException ("no exponent following e or E");
 185:     
 186:         try 
 187:       {
 188:         int exp = Integer.parseInt (num.substring (point));
 189:         exp -= scale;
 190:         if (signum () == 0)
 191:           scale = 0;
 192:         else if (exp > 0)
 193:           {
 194:         intVal = intVal.multiply (BigInteger.valueOf (10).pow (exp));
 195:         scale = 0;
 196:           }
 197:         else
 198:           scale = - exp;
 199:       }
 200:         catch (NumberFormatException ex) 
 201:       {
 202:         throw new NumberFormatException ("malformed exponent");
 203:       }
 204:       }
 205:   }
 206: 
 207:   public static BigDecimal valueOf (long val) 
 208:   {
 209:     return valueOf (val, 0);
 210:   }
 211: 
 212:   public static BigDecimal valueOf (long val, int scale) 
 213:     throws NumberFormatException 
 214:   {
 215:     if ((scale == 0) && ((int)val == val))
 216:       switch ((int) val)
 217:     {
 218:     case 0:
 219:       return ZERO;
 220:     case 1:
 221:       return ONE;
 222:     }
 223: 
 224:     return new BigDecimal (BigInteger.valueOf (val), scale);
 225:   }
 226: 
 227:   public BigDecimal add (BigDecimal val) 
 228:   {
 229:     // For addition, need to line up decimals.  Note that the movePointRight
 230:     // method cannot be used for this as it might return a BigDecimal with
 231:     // scale == 0 instead of the scale we need.
 232:     BigInteger op1 = intVal;
 233:     BigInteger op2 = val.intVal;
 234:     if (scale < val.scale)
 235:       op1 = op1.multiply (BigInteger.valueOf (10).pow (val.scale - scale));
 236:     else if (scale > val.scale)
 237:       op2 = op2.multiply (BigInteger.valueOf (10).pow (scale - val.scale));
 238: 
 239:     return new BigDecimal (op1.add (op2), Math.max (scale, val.scale));
 240:   }
 241: 
 242:   public BigDecimal subtract (BigDecimal val) 
 243:   {
 244:     return this.add(val.negate());
 245:   }
 246: 
 247:   public BigDecimal multiply (BigDecimal val) 
 248:   {
 249:     return new BigDecimal (intVal.multiply (val.intVal), scale + val.scale);
 250:   }
 251: 
 252:   public BigDecimal divide (BigDecimal val, int roundingMode) 
 253:     throws ArithmeticException, IllegalArgumentException 
 254:   {
 255:     return divide (val, scale, roundingMode);
 256:   }
 257: 
 258:   public BigDecimal divide(BigDecimal val, int newScale, int roundingMode)
 259:     throws ArithmeticException, IllegalArgumentException 
 260:   {
 261:     if (roundingMode < 0 || roundingMode > 7)
 262:       throw 
 263:     new IllegalArgumentException("illegal rounding mode: " + roundingMode);
 264: 
 265:     if (newScale < 0)
 266:       throw new ArithmeticException ("scale is negative: " + newScale);
 267: 
 268:     if (intVal.signum () == 0)    // handle special case of 0.0/0.0
 269:       return newScale == 0 ? ZERO : new BigDecimal (ZERO.intVal, newScale);
 270:     
 271:     // Ensure that pow gets a non-negative value.
 272:     BigInteger valIntVal = val.intVal;
 273:     int power = newScale - (scale - val.scale);
 274:     if (power < 0)
 275:       {
 276:     // Effectively increase the scale of val to avoid an
 277:     // ArithmeticException for a negative power.
 278:         valIntVal = valIntVal.multiply (BigInteger.valueOf (10).pow (-power));
 279:     power = 0;
 280:       }
 281: 
 282:     BigInteger dividend = intVal.multiply (BigInteger.valueOf (10).pow (power));
 283:     
 284:     BigInteger parts[] = dividend.divideAndRemainder (valIntVal);
 285: 
 286:     BigInteger unrounded = parts[0];
 287:     if (parts[1].signum () == 0) // no remainder, no rounding necessary
 288:       return new BigDecimal (unrounded, newScale);
 289: 
 290:     if (roundingMode == ROUND_UNNECESSARY)
 291:       throw new ArithmeticException ("newScale is not large enough");
 292: 
 293:     int sign = intVal.signum () * valIntVal.signum ();
 294: 
 295:     if (roundingMode == ROUND_CEILING)
 296:       roundingMode = (sign > 0) ? ROUND_UP : ROUND_DOWN;
 297:     else if (roundingMode == ROUND_FLOOR)
 298:       roundingMode = (sign < 0) ? ROUND_UP : ROUND_DOWN;
 299:     else
 300:       {
 301:     // half is -1 if remainder*2 < positive intValue (*power), 0 if equal,
 302:     // 1 if >. This implies that the remainder to round is less than,
 303:     // equal to, or greater than half way to the next digit.
 304:     BigInteger posRemainder
 305:       = parts[1].signum () < 0 ? parts[1].negate() : parts[1];
 306:     valIntVal = valIntVal.signum () < 0 ? valIntVal.negate () : valIntVal;
 307:     int half = posRemainder.shiftLeft(1).compareTo(valIntVal);
 308: 
 309:     switch(roundingMode)
 310:       {
 311:       case ROUND_HALF_UP:
 312:         roundingMode = (half < 0) ? ROUND_DOWN : ROUND_UP;
 313:         break;
 314:       case ROUND_HALF_DOWN:
 315:         roundingMode = (half > 0) ? ROUND_UP : ROUND_DOWN;
 316:         break;
 317:       case ROUND_HALF_EVEN:
 318:         if (half < 0)
 319:           roundingMode = ROUND_DOWN;
 320:         else if (half > 0)
 321:           roundingMode = ROUND_UP;
 322:         else if (unrounded.testBit(0)) // odd, then ROUND_HALF_UP
 323:           roundingMode = ROUND_UP;
 324:         else                           // even, ROUND_HALF_DOWN
 325:           roundingMode = ROUND_DOWN;
 326:         break;
 327:       }
 328:       }
 329: 
 330:     if (roundingMode == ROUND_UP)
 331:       unrounded = unrounded.add (BigInteger.valueOf (sign > 0 ? 1 : -1));
 332: 
 333:     // roundingMode == ROUND_DOWN
 334:     return new BigDecimal (unrounded, newScale);
 335:   }
 336:     
 337:   public int compareTo (BigDecimal val) 
 338:   {
 339:     if (scale == val.scale)
 340:       return intVal.compareTo (val.intVal);
 341: 
 342:     BigInteger thisParts[] = 
 343:       intVal.divideAndRemainder (BigInteger.valueOf (10).pow (scale));
 344:     BigInteger valParts[] =
 345:       val.intVal.divideAndRemainder (BigInteger.valueOf (10).pow (val.scale));
 346:     
 347:     int compare;
 348:     if ((compare = thisParts[0].compareTo (valParts[0])) != 0)
 349:       return compare;
 350: 
 351:     // quotients are the same, so compare remainders
 352: 
 353:     // remove trailing zeros
 354:     if (thisParts[1].equals (BigInteger.valueOf (0)) == false)
 355:       while (thisParts[1].mod (BigInteger.valueOf (10)).equals
 356:          (BigInteger.valueOf (0)))
 357:       thisParts[1] = thisParts[1].divide (BigInteger.valueOf (10));
 358:     // again...
 359:     if (valParts[1].equals(BigInteger.valueOf (0)) == false)
 360:       while (valParts[1].mod (BigInteger.valueOf (10)).equals
 361:          (BigInteger.valueOf (0)))
 362:     valParts[1] = valParts[1].divide (BigInteger.valueOf (10));
 363: 
 364:     // and compare them
 365:     return thisParts[1].compareTo (valParts[1]);
 366:   }
 367: 
 368:   public int compareTo (Object val) 
 369:   {
 370:     return(compareTo((BigDecimal)val));
 371:   }
 372: 
 373:   public boolean equals (Object o) 
 374:   {
 375:     return (o instanceof BigDecimal 
 376:         && scale == ((BigDecimal) o).scale
 377:         && compareTo ((BigDecimal) o) == 0);
 378:   }
 379: 
 380:   public int hashCode() 
 381:   {
 382:     return intValue() ^ scale;
 383:   }
 384: 
 385:   public BigDecimal max (BigDecimal val)
 386:   {
 387:     switch (compareTo (val)) 
 388:       {
 389:       case 1:
 390:     return this;
 391:       default:
 392:     return val;
 393:       }
 394:   }
 395: 
 396:   public BigDecimal min (BigDecimal val) 
 397:   {
 398:     switch (compareTo (val)) 
 399:       {
 400:       case -1:
 401:     return this;
 402:       default:
 403:     return val;
 404:       }
 405:   }
 406: 
 407:   public BigDecimal movePointLeft (int n)
 408:   {
 409:     return (n < 0) ? movePointRight (-n) : new BigDecimal (intVal, scale + n);
 410:   }
 411: 
 412:   public BigDecimal movePointRight (int n)
 413:   {
 414:     if (n < 0)
 415:       return movePointLeft (-n);
 416: 
 417:     if (scale >= n)
 418:       return new BigDecimal (intVal, scale - n);
 419: 
 420:     return new BigDecimal (intVal.multiply 
 421:                (BigInteger.valueOf (10).pow (n - scale)), 0);
 422:   }
 423: 
 424:   public int signum () 
 425:   {
 426:     return intVal.signum ();
 427:   }
 428: 
 429:   public int scale () 
 430:   {
 431:     return scale;
 432:   }
 433:   
 434:   public BigInteger unscaledValue()
 435:   {
 436:     return intVal;
 437:   }
 438: 
 439:   public BigDecimal abs () 
 440:   {
 441:     return new BigDecimal (intVal.abs (), scale);
 442:   }
 443: 
 444:   public BigDecimal negate () 
 445:   {
 446:     return new BigDecimal (intVal.negate (), scale);
 447:   }
 448: 
 449:   public String toString () 
 450:   {
 451:     String bigStr = intVal.toString();
 452:     if (scale == 0) 
 453:       return bigStr;
 454: 
 455:     boolean negative = (bigStr.charAt(0) == '-');
 456: 
 457:     int point = bigStr.length() - scale - (negative ? 1 : 0);
 458: 
 459:     StringBuffer sb = new StringBuffer(bigStr.length() + 2 +
 460:                        (point <= 0 ? (-point + 1) : 0));
 461:     if (point <= 0)
 462:       {
 463:         if (negative)
 464:           sb.append('-');
 465:         sb.append('0').append('.');
 466:         while (point < 0)
 467:           {
 468:             sb.append('0');
 469:             point++;
 470:           }
 471:         sb.append(bigStr.substring(negative ? 1 : 0));
 472:       }
 473:     else
 474:       {
 475:     sb.append(bigStr);
 476:     sb.insert(point + (negative ? 1 : 0), '.');
 477:       }
 478:     return sb.toString();
 479:   }
 480: 
 481:   public BigInteger toBigInteger () 
 482:   {
 483:     return scale == 0 ? intVal :
 484:       intVal.divide (BigInteger.valueOf (10).pow (scale));
 485:   }
 486: 
 487:   public int intValue () 
 488:   {
 489:     return toBigInteger ().intValue ();
 490:   }
 491: 
 492:   public long longValue ()
 493:   {
 494:     return toBigInteger().longValue();
 495:   }
 496: 
 497:   public float floatValue() 
 498:   {
 499:     return Float.valueOf(toString()).floatValue();
 500:   }
 501: 
 502:   public double doubleValue() 
 503:   {
 504:     return Double.valueOf(toString()).doubleValue();
 505:   }
 506: 
 507:   public BigDecimal setScale (int scale) throws ArithmeticException
 508:   {
 509:     return setScale (scale, ROUND_UNNECESSARY);
 510:   }
 511: 
 512:   public BigDecimal setScale (int scale, int roundingMode)
 513:     throws ArithmeticException, IllegalArgumentException
 514:   {
 515:     return divide (ONE, scale, roundingMode);
 516:   }
 517: }