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:   /**
  47:    * The constant zero as a BigDecimal with scale zero.
  48:    * @since 1.5
  49:    */
  50:   public static final BigDecimal ZERO = 
  51:     new BigDecimal (BigInteger.valueOf (0), 0);
  52: 
  53:   /**
  54:    * The constant one as a BigDecimal with scale zero.
  55:    * @since 1.5
  56:    */
  57:   public static final BigDecimal ONE = 
  58:     new BigDecimal (BigInteger.valueOf (1), 0);
  59: 
  60:   /**
  61:    * The constant ten as a BigDecimal with scale zero.
  62:    * @since 1.5
  63:    */
  64:   public static final BigDecimal TEN = 
  65:     new BigDecimal (BigInteger.valueOf (10), 0);
  66: 
  67:   public static final int ROUND_UP = 0;
  68:   public static final int ROUND_DOWN = 1;
  69:   public static final int ROUND_CEILING = 2;
  70:   public static final int ROUND_FLOOR = 3;
  71:   public static final int ROUND_HALF_UP = 4;
  72:   public static final int ROUND_HALF_DOWN = 5;
  73:   public static final int ROUND_HALF_EVEN = 6;
  74:   public static final int ROUND_UNNECESSARY = 7;
  75: 
  76:   public BigDecimal (BigInteger num) 
  77:   {
  78:     this (num, 0);
  79:   }
  80: 
  81:   public BigDecimal (BigInteger num, int scale) throws NumberFormatException 
  82:   {
  83:     if (scale < 0) 
  84:       throw new NumberFormatException ("scale of " + scale + " is < 0");
  85:     this.intVal = num;
  86:     this.scale = scale;
  87:   }
  88: 
  89:   public BigDecimal (double num) throws NumberFormatException 
  90:   {
  91:     if (Double.isInfinite (num) || Double.isNaN (num))
  92:       throw new NumberFormatException ("invalid argument: " + num);
  93:     // Note we can't convert NUM to a String and then use the
  94:     // String-based constructor.  The BigDecimal documentation makes
  95:     // it clear that the two constructors work differently.
  96: 
  97:     final int mantissaBits = 52;
  98:     final int exponentBits = 11;
  99:     final long mantMask = (1L << mantissaBits) - 1;
 100:     final long expMask = (1L << exponentBits) - 1;
 101: 
 102:     long bits = Double.doubleToLongBits (num);
 103:     long mantissa = bits & mantMask;
 104:     long exponent = (bits >>> mantissaBits) & expMask;
 105:     boolean denormal = exponent == 0;
 106:     // Correct the exponent for the bias.
 107:     exponent -= denormal ? 1022 : 1023;
 108:     // Now correct the exponent to account for the bits to the right
 109:     // of the decimal.
 110:     exponent -= mantissaBits;
 111:     // Ordinary numbers have an implied leading `1' bit.
 112:     if (! denormal)
 113:       mantissa |= (1L << mantissaBits);
 114: 
 115:     // Shave off factors of 10.
 116:     while (exponent < 0 && (mantissa & 1) == 0)
 117:       {
 118:     ++exponent;
 119:     mantissa >>= 1;
 120:       }
 121: 
 122:     intVal = BigInteger.valueOf (bits < 0 ? - mantissa : mantissa);
 123:     if (exponent < 0)
 124:       {
 125:     // We have MANTISSA * 2 ^ (EXPONENT).
 126:     // Since (1/2)^N == 5^N * 10^-N we can easily convert this
 127:     // into a power of 10.
 128:     scale = (int) (- exponent);
 129:     BigInteger mult = BigInteger.valueOf (5).pow (scale);
 130:     intVal = intVal.multiply (mult);
 131:       }
 132:     else
 133:       {
 134:     intVal = intVal.shiftLeft ((int) exponent);
 135:     scale = 0;
 136:       }
 137:   }
 138: 
 139:   public BigDecimal (String num) throws NumberFormatException 
 140:   {
 141:     int len = num.length();
 142:     int start = 0, point = 0;
 143:     int dot = -1;
 144:     boolean negative = false;
 145:     if (num.charAt(0) == '+')
 146:       {
 147:     ++start;
 148:     ++point;
 149:       }
 150:     else if (num.charAt(0) == '-')
 151:       {
 152:     ++start;
 153:     ++point;
 154:     negative = true;
 155:       }
 156: 
 157:     while (point < len)
 158:       {
 159:     char c = num.charAt (point);
 160:     if (c == '.')
 161:       {
 162:         if (dot >= 0)
 163:           throw new NumberFormatException ("multiple `.'s in number");
 164:         dot = point;
 165:       }
 166:     else if (c == 'e' || c == 'E')
 167:       break;
 168:     else if (Character.digit (c, 10) < 0)
 169:       throw new NumberFormatException ("unrecognized character: " + c);
 170:     ++point;
 171:       }
 172: 
 173:     String val;
 174:     if (dot >= 0)
 175:       {
 176:     val = num.substring (start, dot) + num.substring (dot + 1, point);
 177:     scale = point - 1 - dot;
 178:       }
 179:     else
 180:       {
 181:     val = num.substring (start, point);
 182:     scale = 0;
 183:       }
 184:     if (val.length () == 0)
 185:       throw new NumberFormatException ("no digits seen");
 186: 
 187:     if (negative)
 188:       val = "-" + val;
 189:     intVal = new BigInteger (val);
 190: 
 191:     // Now parse exponent.
 192:     if (point < len)
 193:       {
 194:         point++;
 195:         if (num.charAt(point) == '+')
 196:           point++;
 197: 
 198:         if (point >= len )
 199:           throw new NumberFormatException ("no exponent following e or E");
 200:     
 201:         try 
 202:       {
 203:         int exp = Integer.parseInt (num.substring (point));
 204:         exp -= scale;
 205:         if (signum () == 0)
 206:           scale = 0;
 207:         else if (exp > 0)
 208:           {
 209:         intVal = intVal.multiply (BigInteger.valueOf (10).pow (exp));
 210:         scale = 0;
 211:           }
 212:         else
 213:           scale = - exp;
 214:       }
 215:         catch (NumberFormatException ex) 
 216:       {
 217:         throw new NumberFormatException ("malformed exponent");
 218:       }
 219:       }
 220:   }
 221: 
 222:   public static BigDecimal valueOf (long val) 
 223:   {
 224:     return valueOf (val, 0);
 225:   }
 226: 
 227:   public static BigDecimal valueOf (long val, int scale) 
 228:     throws NumberFormatException 
 229:   {
 230:     if ((scale == 0) && ((int)val == val))
 231:       switch ((int) val)
 232:     {
 233:     case 0:
 234:       return ZERO;
 235:     case 1:
 236:       return ONE;
 237:     }
 238: 
 239:     return new BigDecimal (BigInteger.valueOf (val), scale);
 240:   }
 241: 
 242:   public BigDecimal add (BigDecimal val) 
 243:   {
 244:     // For addition, need to line up decimals.  Note that the movePointRight
 245:     // method cannot be used for this as it might return a BigDecimal with
 246:     // scale == 0 instead of the scale we need.
 247:     BigInteger op1 = intVal;
 248:     BigInteger op2 = val.intVal;
 249:     if (scale < val.scale)
 250:       op1 = op1.multiply (BigInteger.valueOf (10).pow (val.scale - scale));
 251:     else if (scale > val.scale)
 252:       op2 = op2.multiply (BigInteger.valueOf (10).pow (scale - val.scale));
 253: 
 254:     return new BigDecimal (op1.add (op2), Math.max (scale, val.scale));
 255:   }
 256: 
 257:   public BigDecimal subtract (BigDecimal val) 
 258:   {
 259:     return this.add(val.negate());
 260:   }
 261: 
 262:   public BigDecimal multiply (BigDecimal val) 
 263:   {
 264:     return new BigDecimal (intVal.multiply (val.intVal), scale + val.scale);
 265:   }
 266: 
 267:   public BigDecimal divide (BigDecimal val, int roundingMode) 
 268:     throws ArithmeticException, IllegalArgumentException 
 269:   {
 270:     return divide (val, scale, roundingMode);
 271:   }
 272: 
 273:   public BigDecimal divide(BigDecimal val, int newScale, int roundingMode)
 274:     throws ArithmeticException, IllegalArgumentException 
 275:   {
 276:     if (roundingMode < 0 || roundingMode > 7)
 277:       throw 
 278:     new IllegalArgumentException("illegal rounding mode: " + roundingMode);
 279: 
 280:     if (newScale < 0)
 281:       throw new ArithmeticException ("scale is negative: " + newScale);
 282: 
 283:     if (intVal.signum () == 0)    // handle special case of 0.0/0.0
 284:       return newScale == 0 ? ZERO : new BigDecimal (ZERO.intVal, newScale);
 285:     
 286:     // Ensure that pow gets a non-negative value.
 287:     BigInteger valIntVal = val.intVal;
 288:     int power = newScale - (scale - val.scale);
 289:     if (power < 0)
 290:       {
 291:     // Effectively increase the scale of val to avoid an
 292:     // ArithmeticException for a negative power.
 293:         valIntVal = valIntVal.multiply (BigInteger.valueOf (10).pow (-power));
 294:     power = 0;
 295:       }
 296: 
 297:     BigInteger dividend = intVal.multiply (BigInteger.valueOf (10).pow (power));
 298:     
 299:     BigInteger parts[] = dividend.divideAndRemainder (valIntVal);
 300: 
 301:     BigInteger unrounded = parts[0];
 302:     if (parts[1].signum () == 0) // no remainder, no rounding necessary
 303:       return new BigDecimal (unrounded, newScale);
 304: 
 305:     if (roundingMode == ROUND_UNNECESSARY)
 306:       throw new ArithmeticException ("newScale is not large enough");
 307: 
 308:     int sign = intVal.signum () * valIntVal.signum ();
 309: 
 310:     if (roundingMode == ROUND_CEILING)
 311:       roundingMode = (sign > 0) ? ROUND_UP : ROUND_DOWN;
 312:     else if (roundingMode == ROUND_FLOOR)
 313:       roundingMode = (sign < 0) ? ROUND_UP : ROUND_DOWN;
 314:     else
 315:       {
 316:     // half is -1 if remainder*2 < positive intValue (*power), 0 if equal,
 317:     // 1 if >. This implies that the remainder to round is less than,
 318:     // equal to, or greater than half way to the next digit.
 319:     BigInteger posRemainder
 320:       = parts[1].signum () < 0 ? parts[1].negate() : parts[1];
 321:     valIntVal = valIntVal.signum () < 0 ? valIntVal.negate () : valIntVal;
 322:     int half = posRemainder.shiftLeft(1).compareTo(valIntVal);
 323: 
 324:     switch(roundingMode)
 325:       {
 326:       case ROUND_HALF_UP:
 327:         roundingMode = (half < 0) ? ROUND_DOWN : ROUND_UP;
 328:         break;
 329:       case ROUND_HALF_DOWN:
 330:         roundingMode = (half > 0) ? ROUND_UP : ROUND_DOWN;
 331:         break;
 332:       case ROUND_HALF_EVEN:
 333:         if (half < 0)
 334:           roundingMode = ROUND_DOWN;
 335:         else if (half > 0)
 336:           roundingMode = ROUND_UP;
 337:         else if (unrounded.testBit(0)) // odd, then ROUND_HALF_UP
 338:           roundingMode = ROUND_UP;
 339:         else                           // even, ROUND_HALF_DOWN
 340:           roundingMode = ROUND_DOWN;
 341:         break;
 342:       }
 343:       }
 344: 
 345:     if (roundingMode == ROUND_UP)
 346:       unrounded = unrounded.add (BigInteger.valueOf (sign > 0 ? 1 : -1));
 347: 
 348:     // roundingMode == ROUND_DOWN
 349:     return new BigDecimal (unrounded, newScale);
 350:   }
 351:     
 352:   public int compareTo (BigDecimal val) 
 353:   {
 354:     if (scale == val.scale)
 355:       return intVal.compareTo (val.intVal);
 356: 
 357:     BigInteger thisParts[] = 
 358:       intVal.divideAndRemainder (BigInteger.valueOf (10).pow (scale));
 359:     BigInteger valParts[] =
 360:       val.intVal.divideAndRemainder (BigInteger.valueOf (10).pow (val.scale));
 361:     
 362:     int compare;
 363:     if ((compare = thisParts[0].compareTo (valParts[0])) != 0)
 364:       return compare;
 365: 
 366:     // quotients are the same, so compare remainders
 367: 
 368:     // remove trailing zeros
 369:     if (thisParts[1].equals (BigInteger.valueOf (0)) == false)
 370:       while (thisParts[1].mod (BigInteger.valueOf (10)).equals
 371:          (BigInteger.valueOf (0)))
 372:       thisParts[1] = thisParts[1].divide (BigInteger.valueOf (10));
 373:     // again...
 374:     if (valParts[1].equals(BigInteger.valueOf (0)) == false)
 375:       while (valParts[1].mod (BigInteger.valueOf (10)).equals
 376:          (BigInteger.valueOf (0)))
 377:     valParts[1] = valParts[1].divide (BigInteger.valueOf (10));
 378: 
 379:     // and compare them
 380:     return thisParts[1].compareTo (valParts[1]);
 381:   }
 382: 
 383:   public int compareTo (Object val) 
 384:   {
 385:     return(compareTo((BigDecimal)val));
 386:   }
 387: 
 388:   public boolean equals (Object o) 
 389:   {
 390:     return (o instanceof BigDecimal 
 391:         && scale == ((BigDecimal) o).scale
 392:         && compareTo ((BigDecimal) o) == 0);
 393:   }
 394: 
 395:   public int hashCode() 
 396:   {
 397:     return intValue() ^ scale;
 398:   }
 399: 
 400:   public BigDecimal max (BigDecimal val)
 401:   {
 402:     switch (compareTo (val)) 
 403:       {
 404:       case 1:
 405:     return this;
 406:       default:
 407:     return val;
 408:       }
 409:   }
 410: 
 411:   public BigDecimal min (BigDecimal val) 
 412:   {
 413:     switch (compareTo (val)) 
 414:       {
 415:       case -1:
 416:     return this;
 417:       default:
 418:     return val;
 419:       }
 420:   }
 421: 
 422:   public BigDecimal movePointLeft (int n)
 423:   {
 424:     return (n < 0) ? movePointRight (-n) : new BigDecimal (intVal, scale + n);
 425:   }
 426: 
 427:   public BigDecimal movePointRight (int n)
 428:   {
 429:     if (n < 0)
 430:       return movePointLeft (-n);
 431: 
 432:     if (scale >= n)
 433:       return new BigDecimal (intVal, scale - n);
 434: 
 435:     return new BigDecimal (intVal.multiply 
 436:                (BigInteger.valueOf (10).pow (n - scale)), 0);
 437:   }
 438: 
 439:   public int signum () 
 440:   {
 441:     return intVal.signum ();
 442:   }
 443: 
 444:   public int scale () 
 445:   {
 446:     return scale;
 447:   }
 448:   
 449:   public BigInteger unscaledValue()
 450:   {
 451:     return intVal;
 452:   }
 453: 
 454:   public BigDecimal abs () 
 455:   {
 456:     return new BigDecimal (intVal.abs (), scale);
 457:   }
 458: 
 459:   public BigDecimal negate () 
 460:   {
 461:     return new BigDecimal (intVal.negate (), scale);
 462:   }
 463: 
 464:   public String toString () 
 465:   {
 466:     String bigStr = intVal.toString();
 467:     if (scale == 0) 
 468:       return bigStr;
 469: 
 470:     boolean negative = (bigStr.charAt(0) == '-');
 471: 
 472:     int point = bigStr.length() - scale - (negative ? 1 : 0);
 473: 
 474:     StringBuffer sb = new StringBuffer(bigStr.length() + 2 +
 475:                        (point <= 0 ? (-point + 1) : 0));
 476:     if (point <= 0)
 477:       {
 478:         if (negative)
 479:           sb.append('-');
 480:         sb.append('0').append('.');
 481:         while (point < 0)
 482:           {
 483:             sb.append('0');
 484:             point++;
 485:           }
 486:         sb.append(bigStr.substring(negative ? 1 : 0));
 487:       }
 488:     else
 489:       {
 490:     sb.append(bigStr);
 491:     sb.insert(point + (negative ? 1 : 0), '.');
 492:       }
 493:     return sb.toString();
 494:   }
 495: 
 496:   public BigInteger toBigInteger () 
 497:   {
 498:     return scale == 0 ? intVal :
 499:       intVal.divide (BigInteger.valueOf (10).pow (scale));
 500:   }
 501: 
 502:   public int intValue () 
 503:   {
 504:     return toBigInteger ().intValue ();
 505:   }
 506: 
 507:   public long longValue ()
 508:   {
 509:     return toBigInteger().longValue();
 510:   }
 511: 
 512:   public float floatValue() 
 513:   {
 514:     return Float.valueOf(toString()).floatValue();
 515:   }
 516: 
 517:   public double doubleValue() 
 518:   {
 519:     return Double.valueOf(toString()).doubleValue();
 520:   }
 521: 
 522:   public BigDecimal setScale (int scale) throws ArithmeticException
 523:   {
 524:     return setScale (scale, ROUND_UNNECESSARY);
 525:   }
 526: 
 527:   public BigDecimal setScale (int scale, int roundingMode)
 528:     throws ArithmeticException, IllegalArgumentException
 529:   {
 530:     return divide (ONE, scale, roundingMode);
 531:   }
 532: }