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:     // Add some trailing zeros to the remainder with the smallest scale
 369:     if (scale < val.scale)
 370:       thisParts[1] = thisParts[1].multiply
 371:             (BigInteger.valueOf (10).pow (val.scale - scale));
 372:     else if (scale > val.scale)
 373:       valParts[1] = valParts[1].multiply
 374:             (BigInteger.valueOf (10).pow (scale - val.scale));
 375: 
 376:     // and compare them
 377:     return thisParts[1].compareTo (valParts[1]);
 378:   }
 379: 
 380:   public int compareTo (Object val) 
 381:   {
 382:     return(compareTo((BigDecimal)val));
 383:   }
 384: 
 385:   public boolean equals (Object o) 
 386:   {
 387:     return (o instanceof BigDecimal 
 388:         && scale == ((BigDecimal) o).scale
 389:         && compareTo ((BigDecimal) o) == 0);
 390:   }
 391: 
 392:   public int hashCode() 
 393:   {
 394:     return intValue() ^ scale;
 395:   }
 396: 
 397:   public BigDecimal max (BigDecimal val)
 398:   {
 399:     switch (compareTo (val)) 
 400:       {
 401:       case 1:
 402:     return this;
 403:       default:
 404:     return val;
 405:       }
 406:   }
 407: 
 408:   public BigDecimal min (BigDecimal val) 
 409:   {
 410:     switch (compareTo (val)) 
 411:       {
 412:       case -1:
 413:     return this;
 414:       default:
 415:     return val;
 416:       }
 417:   }
 418: 
 419:   public BigDecimal movePointLeft (int n)
 420:   {
 421:     return (n < 0) ? movePointRight (-n) : new BigDecimal (intVal, scale + n);
 422:   }
 423: 
 424:   public BigDecimal movePointRight (int n)
 425:   {
 426:     if (n < 0)
 427:       return movePointLeft (-n);
 428: 
 429:     if (scale >= n)
 430:       return new BigDecimal (intVal, scale - n);
 431: 
 432:     return new BigDecimal (intVal.multiply 
 433:                (BigInteger.valueOf (10).pow (n - scale)), 0);
 434:   }
 435: 
 436:   public int signum () 
 437:   {
 438:     return intVal.signum ();
 439:   }
 440: 
 441:   public int scale () 
 442:   {
 443:     return scale;
 444:   }
 445:   
 446:   public BigInteger unscaledValue()
 447:   {
 448:     return intVal;
 449:   }
 450: 
 451:   public BigDecimal abs () 
 452:   {
 453:     return new BigDecimal (intVal.abs (), scale);
 454:   }
 455: 
 456:   public BigDecimal negate () 
 457:   {
 458:     return new BigDecimal (intVal.negate (), scale);
 459:   }
 460: 
 461:   public String toString () 
 462:   {
 463:     String bigStr = intVal.toString();
 464:     if (scale == 0) 
 465:       return bigStr;
 466: 
 467:     boolean negative = (bigStr.charAt(0) == '-');
 468: 
 469:     int point = bigStr.length() - scale - (negative ? 1 : 0);
 470: 
 471:     StringBuffer sb = new StringBuffer(bigStr.length() + 2 +
 472:                        (point <= 0 ? (-point + 1) : 0));
 473:     if (point <= 0)
 474:       {
 475:         if (negative)
 476:           sb.append('-');
 477:         sb.append('0').append('.');
 478:         while (point < 0)
 479:           {
 480:             sb.append('0');
 481:             point++;
 482:           }
 483:         sb.append(bigStr.substring(negative ? 1 : 0));
 484:       }
 485:     else
 486:       {
 487:     sb.append(bigStr);
 488:     sb.insert(point + (negative ? 1 : 0), '.');
 489:       }
 490:     return sb.toString();
 491:   }
 492: 
 493:   public BigInteger toBigInteger () 
 494:   {
 495:     return scale == 0 ? intVal :
 496:       intVal.divide (BigInteger.valueOf (10).pow (scale));
 497:   }
 498: 
 499:   public int intValue () 
 500:   {
 501:     return toBigInteger ().intValue ();
 502:   }
 503: 
 504:   public long longValue ()
 505:   {
 506:     return toBigInteger().longValue();
 507:   }
 508: 
 509:   public float floatValue() 
 510:   {
 511:     return Float.valueOf(toString()).floatValue();
 512:   }
 513: 
 514:   public double doubleValue() 
 515:   {
 516:     return Double.valueOf(toString()).doubleValue();
 517:   }
 518: 
 519:   public BigDecimal setScale (int scale) throws ArithmeticException
 520:   {
 521:     return setScale (scale, ROUND_UNNECESSARY);
 522:   }
 523: 
 524:   public BigDecimal setScale (int scale, int roundingMode)
 525:     throws ArithmeticException, IllegalArgumentException
 526:   {
 527:     return divide (ONE, scale, roundingMode);
 528:   }
 529: }