1 7 8 18 19 package java.math; 20 21 205 public class BigDecimal extends Number implements Comparable <BigDecimal > { 206 213 private volatile BigInteger intVal; 214 215 221 private int scale = 0; 232 private volatile transient int precision = 0; 233 234 237 private volatile transient String stringCache = null; 238 239 243 private static final long INFLATED = Long.MIN_VALUE; 244 245 250 private transient long intCompact = INFLATED; 251 252 private static final int MAX_COMPACT_DIGITS = 18; 255 256 private static final int MAX_BIGINT_BITS = 62; 257 258 259 private static final long serialVersionUID = 6108874887143696463L; 260 261 private static final BigDecimal zeroThroughTen[] = { 263 new BigDecimal (BigInteger.ZERO, 0, 0), 264 new BigDecimal (BigInteger.ONE, 1, 0), 265 new BigDecimal (BigInteger.valueOf(2), 2, 0), 266 new BigDecimal (BigInteger.valueOf(3), 3, 0), 267 new BigDecimal (BigInteger.valueOf(4), 4, 0), 268 new BigDecimal (BigInteger.valueOf(5), 5, 0), 269 new BigDecimal (BigInteger.valueOf(6), 6, 0), 270 new BigDecimal (BigInteger.valueOf(7), 7, 0), 271 new BigDecimal (BigInteger.valueOf(8), 8, 0), 272 new BigDecimal (BigInteger.valueOf(9), 9, 0), 273 new BigDecimal (BigInteger.TEN, 10, 0), 274 }; 275 276 282 public static final BigDecimal ZERO = 283 zeroThroughTen[0]; 284 285 290 public static final BigDecimal ONE = 291 zeroThroughTen[1]; 292 293 298 public static final BigDecimal TEN = 299 zeroThroughTen[10]; 300 301 303 322 public BigDecimal(char[] in, int offset, int len) { 323 328 try { 331 boolean isneg = false; if (in[offset] == '-') { 334 isneg = true; offset++; 336 len--; 337 } else if (in[offset] == '+') { offset++; 339 len--; 340 } 341 342 int dotoff = -1; int cfirst = offset; long exp = 0; if (len > in.length) throw new NumberFormatException (); 348 char coeff[] = new char[len]; char c; 351 for (; len > 0; offset++, len--) { 352 c = in[offset]; 353 if ((c >= '0' && c <= '9') || Character.isDigit(c)) { 354 coeff[precision] = c; 356 precision++; continue; 358 } 359 if (c == '.') { 360 if (dotoff >= 0) throw new NumberFormatException (); 363 dotoff = offset; 364 continue; 365 } 366 if ((c != 'e') && (c != 'E')) 368 throw new NumberFormatException (); 369 offset++; 370 c = in[offset]; 371 len--; 372 boolean negexp = false; 373 if (c == '-' || c == '+') { 375 negexp = (c == '-'); 376 offset++; 377 c = in[offset]; 378 len--; 379 } 380 if (len <= 0) throw new NumberFormatException (); 382 while (len > 10 && Character.digit(c, 10) == 0) { 384 offset++; 385 c = in[offset]; 386 len--; 387 } 388 if (len > 10) throw new NumberFormatException (); 390 for (;; len--) { 392 int v; 393 if (c >= '0' && c <= '9') { 394 v = c - '0'; 395 } else { 396 v = Character.digit(c, 10); 397 if (v < 0) throw new NumberFormatException (); 399 } 400 exp = exp * 10 + v; 401 if (len == 1) 402 break; offset++; 404 c = in[offset]; 405 } 406 if (negexp) exp = -exp; 408 if ((int)exp != exp) throw new NumberFormatException (); 411 break; } 413 if (precision == 0) throw new NumberFormatException (); 416 417 if (dotoff >= 0) { scale = precision - (dotoff - cfirst); 419 } 421 if (exp != 0) { try { 423 scale = checkScale(-exp + scale); } catch (ArithmeticException e) { 425 throw new NumberFormatException ("Scale out of range."); 426 } 427 } 428 429 int first = 0; 431 for (; (coeff[first] == '0' || Character.digit(coeff[first], 10) == 0) && 432 precision > 1; 433 first++) 434 precision--; 435 436 char quick[]; 443 if (!isneg) { 444 quick = new char[precision]; 445 System.arraycopy(coeff, first, quick, 0, precision); 446 } else { 447 quick = new char[precision+1]; 448 quick[0] = '-'; 449 System.arraycopy(coeff, first, quick, 1, precision); 450 } 451 if (precision <= MAX_COMPACT_DIGITS) 452 intCompact = Long.parseLong(new String (quick)); 453 else 454 intVal = new BigInteger (quick); 455 } catch (ArrayIndexOutOfBoundsException e) { 457 throw new NumberFormatException (); 458 } catch (NegativeArraySizeException e) { 459 throw new NumberFormatException (); 460 } 461 } 462 463 486 public BigDecimal(char[] in, int offset, int len, MathContext mc) { 487 this(in, offset, len); 488 if (mc.precision > 0) 489 roundThis(mc); 490 } 491 492 508 public BigDecimal(char[] in) { 509 this(in, 0, in.length); 510 } 511 512 532 public BigDecimal(char[] in, MathContext mc) { 533 this(in, 0, in.length, mc); 534 } 535 536 646 public BigDecimal(String val) { 647 this(val.toCharArray(), 0, val.length()); 648 } 649 650 664 public BigDecimal(String val, MathContext mc) { 665 this(val.toCharArray(), 0, val.length()); 666 if (mc.precision > 0) 667 roundThis(mc); 668 } 669 670 714 public BigDecimal(double val) { 715 if (Double.isInfinite(val) || Double.isNaN(val)) 716 throw new NumberFormatException ("Infinite or NaN"); 717 718 long valBits = Double.doubleToLongBits(val); 721 int sign = ((valBits >> 63)==0 ? 1 : -1); 722 int exponent = (int) ((valBits >> 52) & 0x7ffL); 723 long significand = (exponent==0 ? (valBits & ((1L<<52) - 1)) << 1 724 : (valBits & ((1L<<52) - 1)) | (1L<<52)); 725 exponent -= 1075; 726 728 732 if (significand == 0) { 733 intVal = BigInteger.ZERO; 734 intCompact = 0; 735 precision = 1; 736 return; 737 } 738 739 while((significand & 1) == 0) { significand >>= 1; 742 exponent++; 743 } 744 745 intVal = BigInteger.valueOf(sign*significand); 747 if (exponent < 0) { 748 intVal = intVal.multiply(BigInteger.valueOf(5).pow(-exponent)); 749 scale = -exponent; 750 } else if (exponent > 0) { 751 intVal = intVal.multiply(BigInteger.valueOf(2).pow(exponent)); 752 } 753 if (intVal.bitLength() <= MAX_BIGINT_BITS) { 754 intCompact = intVal.longValue(); 755 } 756 } 757 758 776 public BigDecimal(double val, MathContext mc) { 777 this(val); 778 if (mc.precision > 0) 779 roundThis(mc); 780 } 781 782 789 public BigDecimal(BigInteger val) { 790 intVal = val; 791 if (val.bitLength() <= MAX_BIGINT_BITS) { 792 intCompact = val.longValue(); 793 } 794 } 795 796 808 public BigDecimal(BigInteger val, MathContext mc) { 809 intVal = val; 810 if (mc.precision > 0) 811 roundThis(mc); 812 } 813 814 823 public BigDecimal(BigInteger unscaledVal, int scale) { 824 intVal = unscaledVal; 826 this.scale = scale; 827 if (unscaledVal.bitLength() <= MAX_BIGINT_BITS) { 828 intCompact = unscaledVal.longValue(); 829 } 830 } 831 832 847 public BigDecimal(BigInteger unscaledVal, int scale, MathContext mc) { 848 intVal = unscaledVal; 849 this.scale = scale; 850 if (mc.precision > 0) 851 roundThis(mc); 852 } 853 854 862 public BigDecimal(int val) { 863 intCompact = val; 864 } 865 866 877 public BigDecimal(int val, MathContext mc) { 878 intCompact = val; 879 if (mc.precision > 0) 880 roundThis(mc); 881 } 882 883 890 public BigDecimal(long val) { 891 if (compactLong(val)) 892 intCompact = val; 893 else 894 intVal = BigInteger.valueOf(val); 895 } 896 897 908 public BigDecimal(long val, MathContext mc) { 909 if (compactLong(val)) 910 intCompact = val; 911 else 912 intVal = BigInteger.valueOf(val); 913 if (mc.precision > 0) 914 roundThis(mc); 915 } 916 917 920 private BigDecimal(long val, int scale) { 921 this.intCompact = val; 922 this.scale = scale; 923 } 924 925 928 private BigDecimal(BigInteger intVal, long val, int scale) { 929 this.intVal = intVal; 930 this.intCompact = val; 931 this.scale = scale; 932 } 933 934 936 948 public static BigDecimal valueOf(long unscaledVal, int scale) { 949 if (scale == 0 && unscaledVal >= 0 && unscaledVal <= 10) { 950 return zeroThroughTen[(int)unscaledVal]; 951 } 952 if (compactLong(unscaledVal)) 953 return new BigDecimal (unscaledVal, scale); 954 return new BigDecimal (BigInteger.valueOf(unscaledVal), scale); 955 } 956 957 967 public static BigDecimal valueOf(long val) { 968 return valueOf(val, 0); 969 } 970 971 988 public static BigDecimal valueOf(double val) { 989 return new BigDecimal (Double.toString(val)); 994 } 995 996 1005 public BigDecimal add(BigDecimal augend) { 1006 BigDecimal arg[] = {this, augend}; 1007 matchScale(arg); 1008 1009 long x = arg[0].intCompact; 1010 long y = arg[1].intCompact; 1011 1012 if (x != INFLATED && y != INFLATED) { 1015 long sum = x + y; 1016 1023 if ( (((sum ^ x) & (sum ^ y)) >> 63) == 0L ) return BigDecimal.valueOf(sum, arg[0].scale); 1025 } 1026 return new BigDecimal (arg[0].inflate().intVal.add(arg[1].inflate().intVal), arg[0].scale); 1027 } 1028 1029 1043 public BigDecimal add(BigDecimal augend, MathContext mc) { 1044 if (mc.precision == 0) 1045 return add(augend); 1046 BigDecimal lhs = this; 1047 1048 this.inflate(); 1050 augend.inflate(); 1051 1052 { 1055 boolean lhsIsZero = lhs.signum() == 0; 1056 boolean augendIsZero = augend.signum() == 0; 1057 1058 if (lhsIsZero || augendIsZero) { 1059 int preferredScale = Math.max(lhs.scale(), augend.scale()); 1060 BigDecimal result; 1061 1062 if (lhsIsZero && augendIsZero) 1064 return new BigDecimal (BigInteger.ZERO, 0, preferredScale); 1065 1066 1067 result = lhsIsZero ? augend.doRound(mc) : lhs.doRound(mc); 1068 1069 if (result.scale() == preferredScale) 1070 return result; 1071 else if (result.scale() > preferredScale) 1072 return new BigDecimal (result.intVal, result.intCompact, result.scale). 1073 stripZerosToMatchScale(preferredScale); 1074 else { int precisionDiff = mc.precision - result.precision(); 1076 int scaleDiff = preferredScale - result.scale(); 1077 1078 if (precisionDiff >= scaleDiff) 1079 return result.setScale(preferredScale); else 1081 return result.setScale(result.scale() + precisionDiff); 1082 } 1083 } 1084 } 1085 1086 long padding = (long)lhs.scale - augend.scale; 1087 if (padding != 0) { BigDecimal arg[] = preAlign(lhs, augend, padding, mc); 1089 matchScale(arg); 1090 lhs = arg[0]; 1091 augend = arg[1]; 1092 } 1093 1094 return new BigDecimal (lhs.inflate().intVal.add(augend.inflate().intVal), 1095 lhs.scale).doRound(mc); 1096 } 1097 1098 1120 private BigDecimal [] preAlign(BigDecimal lhs, BigDecimal augend, 1121 long padding, MathContext mc) { 1122 assert padding != 0; 1123 BigDecimal big; 1124 BigDecimal small; 1125 1126 if (padding < 0) { big = lhs; 1128 small = augend; 1129 } else { big = augend; 1131 small = lhs; 1132 } 1133 1134 1140 long estResultUlpScale = (long)big.scale - big.precision() + mc.precision; 1141 1142 1151 long smallHighDigitPos = (long)small.scale - small.precision() + 1; 1152 if (smallHighDigitPos > big.scale + 2 && smallHighDigitPos > estResultUlpScale + 2) { small = BigDecimal.valueOf(small.signum(), 1155 this.checkScale(Math.max(big.scale, estResultUlpScale) + 3)); 1156 } 1157 1158 BigDecimal [] result = {big, small}; 1161 return result; 1162 } 1163 1164 1172 public BigDecimal subtract(BigDecimal subtrahend) { 1173 BigDecimal arg[] = {this, subtrahend}; 1174 matchScale(arg); 1175 1176 long x = arg[0].intCompact; 1177 long y = arg[1].intCompact; 1178 1179 if (x != INFLATED && y != INFLATED) { 1182 long difference = x - y; 1183 1190 if ( ((x ^ y) & (difference ^ x) ) >> 63 == 0L ) return BigDecimal.valueOf(difference, arg[0].scale); 1192 } 1193 return new BigDecimal (arg[0].inflate().intVal.subtract(arg[1].inflate().intVal), 1194 arg[0].scale); 1195 } 1196 1197 1211 public BigDecimal subtract(BigDecimal subtrahend, MathContext mc) { 1212 if (mc.precision == 0) 1213 return subtract(subtrahend); 1214 this.inflate(); 1216 subtrahend.inflate(); 1217 BigDecimal rhs = new BigDecimal (subtrahend.intVal.negate(), subtrahend.scale); 1218 rhs.precision = subtrahend.precision; 1219 return add(rhs, mc); 1220 } 1221 1222 1230 public BigDecimal multiply(BigDecimal multiplicand) { 1231 long x = this.intCompact; 1232 long y = multiplicand.intCompact; 1233 int productScale = checkScale((long)scale+multiplicand.scale); 1234 1235 if (x != INFLATED && y != INFLATED) { 1238 1245 long product = x * y; 1246 if ( !(y != 0L && product/y != x) ) return BigDecimal.valueOf(product, productScale); 1248 } 1249 1250 BigDecimal result = new BigDecimal (this.inflate().intVal.multiply(multiplicand.inflate().intVal), productScale); 1251 return result; 1252 } 1253 1254 1265 public BigDecimal multiply(BigDecimal multiplicand, MathContext mc) { 1266 if (mc.precision == 0) 1267 return multiply(multiplicand); 1268 BigDecimal lhs = this; 1269 return lhs.inflate().multiply(multiplicand.inflate()).doRound(mc); 1270 } 1271 1272 1300 public BigDecimal divide(BigDecimal divisor, int scale, int roundingMode) { 1301 1306 if (roundingMode < ROUND_UP || roundingMode > ROUND_UNNECESSARY) 1307 throw new IllegalArgumentException ("Invalid rounding mode"); 1308 1313 BigDecimal dividend; 1314 if (checkScale((long)scale + divisor.scale) >= this.scale) { 1315 dividend = this.setScale(scale + divisor.scale); 1316 } else { 1317 dividend = this; 1318 divisor = divisor.setScale(checkScale((long)this.scale - scale)); 1319 } 1320 1321 boolean compact = dividend.intCompact != INFLATED && divisor.intCompact != INFLATED; 1322 long div = INFLATED; 1323 long rem = INFLATED;; 1324 BigInteger q=null, r=null; 1325 1326 if (compact) { 1327 div = dividend.intCompact / divisor.intCompact; 1328 rem = dividend.intCompact % divisor.intCompact; 1329 } else { 1330 BigInteger i[] = dividend.inflate().intVal.divideAndRemainder(divisor.inflate().intVal); 1332 q = i[0]; 1333 r = i[1]; 1334 } 1335 1336 if (compact) { 1338 if (rem == 0) 1339 return new BigDecimal (div, scale); 1340 } else { 1341 if (r.signum() == 0) 1342 return new BigDecimal (q, scale); 1343 } 1344 1345 if (roundingMode == ROUND_UNNECESSARY) throw new ArithmeticException ("Rounding necessary"); 1347 1348 1349 int signum = dividend.signum() * divisor.signum(); boolean increment; 1351 if (roundingMode == ROUND_UP) { increment = true; 1353 } else if (roundingMode == ROUND_DOWN) { increment = false; 1355 } else if (roundingMode == ROUND_CEILING) { increment = (signum > 0); 1357 } else if (roundingMode == ROUND_FLOOR) { increment = (signum < 0); 1359 } else { int cmpFracHalf; 1361 if (compact) { 1362 cmpFracHalf = longCompareTo(Math.abs(2*rem), Math.abs(divisor.intCompact)); 1363 } else { 1364 cmpFracHalf= r.add(r).abs().compareTo(divisor.intVal.abs()); 1366 } 1367 if (cmpFracHalf < 0) { increment = false; 1369 } else if (cmpFracHalf > 0) { increment = true; 1371 } else { if (roundingMode == ROUND_HALF_UP) 1373 increment = true; 1374 else if (roundingMode == ROUND_HALF_DOWN) 1375 increment = false; 1376 else { if (compact) 1378 increment = (div & 1L) != 0L; 1379 else 1380 increment = q.testBit(0); } 1382 } 1383 } 1384 1385 if (compact) { 1386 if (increment) 1387 div += signum; return new BigDecimal (div, scale); 1389 } else { 1390 return (increment 1391 ? new BigDecimal (q.add(BigInteger.valueOf(signum)), scale) 1392 : new BigDecimal (q, scale)); 1393 } 1394 } 1395 1396 1412 public BigDecimal divide(BigDecimal divisor, int scale, RoundingMode roundingMode) { 1413 return divide(divisor, scale, roundingMode.oldMode); 1414 } 1415 1416 1443 public BigDecimal divide(BigDecimal divisor, int roundingMode) { 1444 return this.divide(divisor, scale, roundingMode); 1445 } 1446 1447 1461 public BigDecimal divide(BigDecimal divisor, RoundingMode roundingMode) { 1462 return this.divide(divisor, scale, roundingMode.oldMode); 1463 } 1464 1465 1479 public BigDecimal divide(BigDecimal divisor) { 1480 1483 if (divisor.signum() == 0) { if (this.signum() == 0) throw new ArithmeticException ("Division undefined"); throw new ArithmeticException ("Division by zero"); 1487 } 1488 1489 int preferredScale = (int)Math.max(Math.min((long)this.scale() - divisor.scale(), 1491 Integer.MAX_VALUE), Integer.MIN_VALUE); 1492 if (this.signum() == 0) return new BigDecimal (0, preferredScale); 1494 else { 1495 this.inflate(); 1496 divisor.inflate(); 1497 1505 MathContext mc = new MathContext ( (int)Math.min(this.precision() + 1506 (long)Math.ceil(10.0*divisor.precision()/3.0), 1507 Integer.MAX_VALUE), 1508 RoundingMode.UNNECESSARY); 1509 BigDecimal quotient; 1510 try { 1511 quotient = this.divide(divisor, mc); 1512 } catch (ArithmeticException e) { 1513 throw new ArithmeticException ("Non-terminating decimal expansion; " + 1514 "no exact representable decimal result."); 1515 } 1516 1517 int quotientScale = quotient.scale(); 1518 1519 1524 if (preferredScale > quotientScale) 1525 return quotient.setScale(preferredScale); 1526 1527 return quotient; 1528 } 1529 } 1530 1531 1544 public BigDecimal divide(BigDecimal divisor, MathContext mc) { 1545 if (mc.precision == 0) 1546 return divide(divisor); 1547 BigDecimal lhs = this.inflate(); BigDecimal rhs = divisor.inflate(); BigDecimal result; 1551 long preferredScale = (long)lhs.scale() - rhs.scale(); 1552 1553 if (rhs.signum() == 0) { if (lhs.signum() == 0) throw new ArithmeticException ("Division undefined"); throw new ArithmeticException ("Division by zero"); 1569 } 1570 if (lhs.signum() == 0) return new BigDecimal (BigInteger.ZERO, 1572 (int)Math.max(Math.min(preferredScale, 1573 Integer.MAX_VALUE), 1574 Integer.MIN_VALUE)); 1575 1576 BigDecimal xprime = new BigDecimal (lhs.intVal.abs(), lhs.precision()); 1577 BigDecimal yprime = new BigDecimal (rhs.intVal.abs(), rhs.precision()); 1578 if (mc.roundingMode == RoundingMode.CEILING || 1580 mc.roundingMode == RoundingMode.FLOOR) { 1581 if ((xprime.signum() != lhs.signum()) ^ 1587 (yprime.signum() != rhs.signum())) { 1588 mc = new MathContext (mc.precision, 1589 (mc.roundingMode==RoundingMode.CEILING)? 1590 RoundingMode.FLOOR:RoundingMode.CEILING); 1591 } 1592 } 1593 1594 if (xprime.compareTo(yprime) > 0) yprime.scale -= 1; result = xprime.divide(yprime, mc.precision, mc.roundingMode.oldMode); 1597 result.scale = checkScale((long)yprime.scale - xprime.scale 1599 - (rhs.scale - lhs.scale) + mc.precision); 1600 if (lhs.signum() != rhs.signum()) 1602 result = result.negate(); 1603 result = result.doRound(mc); 1605 1606 if (result.multiply(divisor).compareTo(this) == 0) { 1607 return result.stripZerosToMatchScale(preferredScale); 1609 } 1610 else { 1611 return result; 1612 } 1613 } 1614 1615 1626 public BigDecimal divideToIntegralValue(BigDecimal divisor) { 1627 int preferredScale = (int)Math.max(Math.min((long)this.scale() - divisor.scale(), 1629 Integer.MAX_VALUE), Integer.MIN_VALUE); 1630 this.inflate(); 1631 divisor.inflate(); 1632 if (this.abs().compareTo(divisor.abs()) < 0) { 1633 return BigDecimal.valueOf(0, preferredScale); 1635 } 1636 1637 if(this.signum() == 0 && divisor.signum() != 0) 1638 return this.setScale(preferredScale); 1639 1640 1643 int maxDigits = (int)Math.min(this.precision() + 1644 (long)Math.ceil(10.0*divisor.precision()/3.0) + 1645 Math.abs((long)this.scale() - divisor.scale()) + 2, 1646 Integer.MAX_VALUE); 1647 1648 BigDecimal quotient = this.divide(divisor, new MathContext (maxDigits, 1649 RoundingMode.DOWN)); 1650 if (quotient.scale > 0) { 1651 quotient = quotient.setScale(0, RoundingMode.DOWN). 1652 stripZerosToMatchScale(preferredScale); 1653 } 1654 1655 if (quotient.scale < preferredScale) { 1656 quotient = quotient.setScale(preferredScale); 1658 } 1659 1660 return quotient; 1661 } 1662 1663 1683 public BigDecimal divideToIntegralValue(BigDecimal divisor, MathContext mc) { 1684 if (mc.precision == 0 || (this.abs().compareTo(divisor.abs()) < 0) ) return divideToIntegralValue(divisor); 1687 1688 int preferredScale = (int)Math.max(Math.min((long)this.scale() - divisor.scale(), 1690 Integer.MAX_VALUE), Integer.MIN_VALUE); 1691 1692 1699 BigDecimal result = this.divide(divisor, new MathContext (mc.precision, 1700 RoundingMode.DOWN)); 1701 int resultScale = result.scale(); 1702 1703 if (result.scale() < 0) { 1704 1709 BigDecimal product = result.multiply(divisor); 1710 if (this.subtract(product).abs().compareTo(divisor.abs()) >= 0) { 1713 throw new ArithmeticException ("Division impossible"); 1714 } 1715 } else if (result.scale() > 0) { 1716 1721 result = result.setScale(0, RoundingMode.DOWN); 1722 } 1723 1725 int precisionDiff; 1726 if ((preferredScale > result.scale()) && 1727 (precisionDiff = mc.precision - result.precision()) > 0 ) { 1728 return result.setScale(result.scale() + 1729 Math.min(precisionDiff, preferredScale - result.scale) ); 1730 } else 1731 return result.stripZerosToMatchScale(preferredScale); 1732 } 1733 1734 1747 public BigDecimal remainder(BigDecimal divisor) { 1748 BigDecimal divrem[] = this.divideAndRemainder(divisor); 1749 return divrem[1]; 1750 } 1751 1752 1753 1777 public BigDecimal remainder(BigDecimal divisor, MathContext mc) { 1778 BigDecimal divrem[] = this.divideAndRemainder(divisor, mc); 1779 return divrem[1]; 1780 } 1781 1782 1802 public BigDecimal [] divideAndRemainder(BigDecimal divisor) { 1803 BigDecimal [] result = new BigDecimal [2]; 1805 1806 result[0] = this.divideToIntegralValue(divisor); 1807 result[1] = this.subtract(result[0].multiply(divisor)); 1808 return result; 1809 } 1810 1811 1837 public BigDecimal [] divideAndRemainder(BigDecimal divisor, MathContext mc) { 1838 if (mc.precision == 0) 1839 return divideAndRemainder(divisor); 1840 1841 BigDecimal [] result = new BigDecimal [2]; 1842 BigDecimal lhs = this; 1843 1844 result[0] = lhs.divideToIntegralValue(divisor, mc); 1845 result[1] = lhs.subtract(result[0].multiply(divisor)); 1846 return result; 1847 } 1848 1849 1866 public BigDecimal pow(int n) { 1867 if (n < 0 || n > 999999999) 1868 throw new ArithmeticException ("Invalid operation"); 1869 int newScale = checkScale((long)scale * n); 1872 this.inflate(); 1873 return new BigDecimal (intVal.pow(n), newScale); 1874 } 1875 1876 1877 1927 public BigDecimal pow(int n, MathContext mc) { 1928 if (mc.precision == 0) 1929 return pow(n); 1930 if (n < -999999999 || n > 999999999) 1931 throw new ArithmeticException ("Invalid operation"); 1932 if (n == 0) 1933 return ONE; this.inflate(); 1935 BigDecimal lhs = this; 1936 MathContext workmc = mc; int mag = Math.abs(n); if (mc.precision > 0) { 1939 1940 int elength = intLength(mag); if (elength > mc.precision) throw new ArithmeticException ("Invalid operation"); 1943 workmc = new MathContext (mc.precision + elength + 1, 1944 mc.roundingMode); 1945 } 1946 BigDecimal acc = ONE; boolean seenbit = false; for (int i=1;;i++) { mag += mag; if (mag < 0) { seenbit = true; acc = acc.multiply(lhs, workmc); } 1955 if (i == 31) 1956 break; if (seenbit) 1958 acc=acc.multiply(acc, workmc); } 1961 if (n<0) acc=ONE.divide(acc, workmc); 1964 return acc.doRound(mc); 1966 } 1967 1968 1975 public BigDecimal abs() { 1976 return (signum() < 0 ? negate() : this); 1977 } 1978 1979 1989 public BigDecimal abs(MathContext mc) { 1990 return (signum() < 0 ? negate(mc) : plus(mc)); 1991 } 1992 1993 1999 public BigDecimal negate() { 2000 BigDecimal result; 2001 if (intCompact != INFLATED) 2002 result = BigDecimal.valueOf(-intCompact, scale); 2003 else { 2004 result = new BigDecimal (intVal.negate(), scale); 2005 result.precision = precision; 2006 } 2007 return result; 2008 } 2009 2010 2020 public BigDecimal negate(MathContext mc) { 2021 return negate().plus(mc); 2022 } 2023 2024 2036 public BigDecimal plus() { 2037 return this; 2038 } 2039 2040 2055 public BigDecimal plus(MathContext mc) { 2056 if (mc.precision == 0) return this; 2058 return this.doRound(mc); 2059 } 2060 2061 2067 public int signum() { 2068 return (intCompact != INFLATED)? 2069 Long.signum(intCompact): 2070 intVal.signum(); 2071 } 2072 2073 2083 public int scale() { 2084 return scale; 2085 } 2086 2087 2096 public int precision() { 2097 int result = precision; 2098 if (result == 0) { 2099 result = digitLength(); 2100 precision = result; 2101 } 2102 return result; 2103 } 2104 2105 2106 2114 public BigInteger unscaledValue() { 2115 return this.inflate().intVal; 2116 } 2117 2118 2120 2125 public final static int ROUND_UP = 0; 2126 2127 2132 public final static int ROUND_DOWN = 1; 2133 2134 2141 public final static int ROUND_CEILING = 2; 2142 2143 2150 public final static int ROUND_FLOOR = 3; 2151 2152 2160 public final static int ROUND_HALF_UP = 4; 2161 2162 2169 public final static int ROUND_HALF_DOWN = 5; 2170 2171 2181 public final static int ROUND_HALF_EVEN = 6; 2182 2183 2189 public final static int ROUND_UNNECESSARY = 7; 2190 2191 2192 2194 2211 public BigDecimal round(MathContext mc) { 2212 return plus(mc); 2213 } 2214 2215 2237 public BigDecimal setScale(int newScale, RoundingMode roundingMode) { 2238 return setScale(newScale, roundingMode.oldMode); 2239 } 2240 2241 2281 public BigDecimal setScale(int newScale, int roundingMode) { 2282 if (roundingMode < ROUND_UP || roundingMode > ROUND_UNNECESSARY) 2283 throw new IllegalArgumentException ("Invalid rounding mode"); 2284 2285 if (newScale == this.scale) return this; 2287 if (this.signum() == 0) return BigDecimal.valueOf(0, newScale); 2289 if (newScale > this.scale) { 2290 int raise = checkScale((long)newScale - this.scale); 2292 2293 if (intCompact != INFLATED) { 2294 long scaledResult = longTenToThe(intCompact, raise); 2295 if (scaledResult != INFLATED) 2296 return BigDecimal.valueOf(scaledResult, newScale); 2297 this.inflate(); 2298 } 2299 2300 BigDecimal result = new BigDecimal (intVal.multiply(tenToThe(raise)), 2301 newScale); 2302 if (this.precision > 0) 2303 result.precision = this.precision + newScale - this.scale; 2304 return result; 2305 } 2306 return divide(ONE, newScale, roundingMode); 2309 } 2310 2311 2347 public BigDecimal setScale(int newScale) { 2348 return setScale(newScale, ROUND_UNNECESSARY); 2349 } 2350 2351 2353 2368 public BigDecimal movePointLeft(int n) { 2369 int newScale = checkScale((long)scale + n); 2371 BigDecimal num; 2372 if (intCompact != INFLATED) 2373 num = BigDecimal.valueOf(intCompact, newScale); 2374 else 2375 num = new BigDecimal (intVal, newScale); 2376 return (num.scale<0 ? num.setScale(0) : num); 2377 } 2378 2379 2394 public BigDecimal movePointRight(int n) { 2395 int newScale = checkScale((long)scale - n); 2397 BigDecimal num; 2398 if (intCompact != INFLATED) 2399 num = BigDecimal.valueOf(intCompact, newScale); 2400 else 2401 num = new BigDecimal (intVal, newScale); 2402 return (num.scale<0 ? num.setScale(0) : num); 2403 } 2404 2405 2415 public BigDecimal scaleByPowerOfTen(int n) { 2416 this.inflate(); 2417 BigDecimal num = new BigDecimal (intVal, checkScale((long)scale - n)); 2418 num.precision = precision; 2419 return num; 2420 } 2421 2422 2434 public BigDecimal stripTrailingZeros() { 2435 this.inflate(); 2436 return (new BigDecimal (intVal, scale)).stripZerosToMatchScale(Long.MIN_VALUE); 2437 } 2438 2439 2441 2457 public int compareTo(BigDecimal val) { 2458 int sigDiff = signum() - val.signum(); 2460 if (sigDiff != 0) 2461 return (sigDiff > 0 ? 1 : -1); 2462 2463 int aethis = this.precision() - this.scale; int aeval = val.precision() - val.scale; if (aethis < aeval) 2468 return -this.signum(); 2469 else if (aethis > aeval) 2470 return this.signum(); 2471 2472 BigDecimal arg[] = {this, val}; 2474 matchScale(arg); 2475 if (arg[0].intCompact != INFLATED && arg[1].intCompact != INFLATED) 2476 return longCompareTo(arg[0].intCompact, arg[1].intCompact); 2477 return arg[0].inflate().intVal.compareTo(arg[1].inflate().intVal); 2478 } 2479 2480 2496 public boolean equals(Object x) { 2497 if (!(x instanceof BigDecimal )) 2498 return false; 2499 BigDecimal xDec = (BigDecimal ) x; 2500 if (scale != xDec.scale) 2501 return false; 2502 if (this.intCompact != INFLATED && xDec.intCompact != INFLATED) 2503 return this.intCompact == xDec.intCompact; 2504 return this.inflate().intVal.equals(xDec.inflate().intVal); 2505 } 2506 2507 2518 public BigDecimal min(BigDecimal val) { 2519 return (compareTo(val) <= 0 ? this : val); 2520 } 2521 2522 2532 public BigDecimal max(BigDecimal val) { 2533 return (compareTo(val) >= 0 ? this : val); 2534 } 2535 2536 2538 2547 public int hashCode() { 2548 if (intCompact != INFLATED) { 2549 long val2 = (intCompact < 0)?-intCompact:intCompact; 2550 int temp = (int)( ((int)(val2 >>> 32)) * 31 + 2551 (val2 & 0xffffffffL)); 2552 return 31*((intCompact < 0) ?-temp:temp) + scale; 2553 } else 2554 return 31*intVal.hashCode() + scale; 2555 } 2556 2557 2559 2658 public String toString() { 2659 if (stringCache == null) 2660 stringCache = layoutChars(true); 2661 return stringCache; 2662 } 2663 2664 2688 public String toEngineeringString() { 2689 return layoutChars(false); 2690 } 2691 2692 2725 public String toPlainString() { 2726 BigDecimal bd = this; 2727 if (bd.scale < 0) 2728 bd = bd.setScale(0); 2729 bd.inflate(); 2730 if (bd.scale == 0) return bd.intVal.toString(); 2732 return bd.getValueString(bd.signum(), bd.intVal.abs().toString(), bd.scale); 2733 } 2734 2735 2736 private String getValueString(int signum, String intString, int scale) { 2737 2738 StringBuilder buf; 2739 int insertionPoint = intString.length() - scale; 2740 if (insertionPoint == 0) { 2741 return (signum<0 ? "-0." : "0.") + intString; 2742 } else if (insertionPoint > 0) { 2743 buf = new StringBuilder (intString); 2744 buf.insert(insertionPoint, '.'); 2745 if (signum < 0) 2746 buf.insert(0, '-'); 2747 } else { 2748 buf = new StringBuilder (3-insertionPoint + intString.length()); 2749 buf.append(signum<0 ? "-0." : "0."); 2750 for (int i=0; i<-insertionPoint; i++) 2751 buf.append('0'); 2752 buf.append(intString); 2753 } 2754 return buf.toString(); 2755 } 2756 2757 2775 public BigInteger toBigInteger() { 2776 return this.setScale(0, ROUND_DOWN).inflate().intVal; 2778 } 2779 2780 2790 public BigInteger toBigIntegerExact() { 2791 return this.setScale(0, ROUND_UNNECESSARY).inflate().intVal; 2793 } 2794 2795 2812 public long longValue(){ 2813 return (intCompact != INFLATED && scale == 0) ? 2814 intCompact: 2815 toBigInteger().longValue(); 2816 } 2817 2818 2830 public long longValueExact() { 2831 if (intCompact != INFLATED && scale == 0) 2832 return intCompact; 2833 if ((precision() - scale) > 19) throw new java.lang.ArithmeticException ("Overflow"); 2836 if (this.signum() == 0) 2839 return 0; 2840 if ((this.precision() - this.scale) <= 0) 2841 throw new ArithmeticException ("Rounding necessary"); 2842 BigDecimal num = this.setScale(0, ROUND_UNNECESSARY).inflate(); 2844 if (num.precision() >= 19) { if (LONGMIN == null) { LONGMIN = BigInteger.valueOf(Long.MIN_VALUE); 2847 LONGMAX = BigInteger.valueOf(Long.MAX_VALUE); 2848 } 2849 if ((num.intVal.compareTo(LONGMIN) < 0) || 2850 (num.intVal.compareTo(LONGMAX) > 0)) 2851 throw new java.lang.ArithmeticException ("Overflow"); 2852 } 2853 return num.intVal.longValue(); 2854 } 2855 2857 private static BigInteger LONGMIN = null; 2858 2859 private static BigInteger LONGMAX = null; 2860 2861 2878 public int intValue() { 2879 return (intCompact != INFLATED && scale == 0) ? 2880 (int)intCompact : 2881 toBigInteger().intValue(); 2882 } 2883 2884 2896 public int intValueExact() { 2897 long num; 2898 num = this.longValueExact(); if ((int)num != num) 2900 throw new java.lang.ArithmeticException ("Overflow"); 2901 return (int)num; 2902 } 2903 2904 2916 public short shortValueExact() { 2917 long num; 2918 num = this.longValueExact(); if ((short)num != num) 2920 throw new java.lang.ArithmeticException ("Overflow"); 2921 return (short)num; 2922 } 2923 2924 2936 public byte byteValueExact() { 2937 long num; 2938 num = this.longValueExact(); if ((byte)num != num) 2940 throw new java.lang.ArithmeticException ("Overflow"); 2941 return (byte)num; 2942 } 2943 2944 2961 public float floatValue(){ 2962 if (scale == 0 && intCompact != INFLATED) 2963 return (float)intCompact; 2964 return Float.parseFloat(this.toString()); 2966 } 2967 2968 2985 public double doubleValue(){ 2986 if (scale == 0 && intCompact != INFLATED) 2987 return (double)intCompact; 2988 return Double.parseDouble(this.toString()); 2990 } 2991 2992 3006 public BigDecimal ulp() { 3007 return BigDecimal.valueOf(1, this.scale()); 3008 } 3009 3010 3012 3021 private String layoutChars(boolean sci) { 3022 if (scale == 0) return (intCompact != INFLATED) ? 3024 Long.toString(intCompact): 3025 intVal.toString(); 3026 3027 char coeff[]; 3029 if (intCompact != INFLATED) 3030 coeff = Long.toString(Math.abs(intCompact)).toCharArray(); 3031 else 3032 coeff = intVal.abs().toString().toCharArray(); 3033 3034 StringBuilder buf=new StringBuilder (coeff.length+14); 3039 if (signum() < 0) buf.append('-'); 3041 long adjusted = -(long)scale + (coeff.length-1); 3042 if ((scale >= 0) && (adjusted >= -6)) { int pad = scale - coeff.length; if (pad >= 0) { buf.append('0'); 3046 buf.append('.'); 3047 for (; pad>0; pad--) { 3048 buf.append('0'); 3049 } 3050 buf.append(coeff); 3051 } else { buf.append(coeff, 0, -pad); 3053 buf.append('.'); 3054 buf.append(coeff, -pad, scale); 3055 } 3056 } else { if (sci) { buf.append(coeff[0]); if (coeff.length > 1) { buf.append('.'); 3061 buf.append(coeff, 1, coeff.length-1); 3062 } 3063 } else { int sig = (int)(adjusted % 3); 3065 if (sig < 0) 3066 sig += 3; adjusted -= sig; sig++; 3069 if (signum() == 0) { 3070 switch (sig) { 3071 case 1: 3072 buf.append('0'); break; 3074 case 2: 3075 buf.append("0.00"); 3076 adjusted += 3; 3077 break; 3078 case 3: 3079 buf.append("0.0"); 3080 adjusted += 3; 3081 break; 3082 default: 3083 throw new AssertionError ("Unexpected sig value " + sig); 3084 } 3085 } else if (sig >= coeff.length) { buf.append(coeff, 0, coeff.length); 3087 for (int i = sig - coeff.length; i > 0; i--) 3089 buf.append('0'); 3090 } else { buf.append(coeff, 0, sig); 3092 buf.append('.'); 3093 buf.append(coeff, sig, coeff.length-sig); 3094 } 3095 } 3096 if (adjusted != 0) { buf.append('E'); 3098 if (adjusted > 0) buf.append('+'); 3100 buf.append(adjusted); 3101 } 3102 } 3103 return buf.toString(); 3104 } 3105 3106 3112 private static BigInteger tenToThe(int n) { 3113 if (n < TENPOWERS.length) return TENPOWERS[n]; 3115 char tenpow[] = new char[n + 1]; 3118 tenpow[0] = '1'; 3119 for (int i = 1; i <= n; i++) 3120 tenpow[i] = '0'; 3121 return new BigInteger (tenpow); 3122 } 3123 private static BigInteger TENPOWERS[] = {BigInteger.ONE, 3124 BigInteger.valueOf(10), BigInteger.valueOf(100), 3125 BigInteger.valueOf(1000), BigInteger.valueOf(10000), 3126 BigInteger.valueOf(100000), BigInteger.valueOf(1000000), 3127 BigInteger.valueOf(10000000), BigInteger.valueOf(100000000), 3128 BigInteger.valueOf(1000000000)}; 3129 3130 3134 private static long longTenToThe(long val, int n) { 3135 if (n >= 0 && n < thresholds.length) { 3137 if (Math.abs(val) <= thresholds[n][0] ) { 3138 return val * thresholds[n][1]; 3140 } 3141 } 3142 return INFLATED; 3144 } 3145 3146 private static long thresholds[][] = { 3147 {Long.MAX_VALUE, 1L}, {Long.MAX_VALUE/10L, 10L}, {Long.MAX_VALUE/100L, 100L}, {Long.MAX_VALUE/1000L, 1000L}, {Long.MAX_VALUE/10000L, 10000L}, {Long.MAX_VALUE/100000L, 100000L}, {Long.MAX_VALUE/1000000L, 1000000L}, {Long.MAX_VALUE/10000000L, 10000000L}, {Long.MAX_VALUE/100000000L, 100000000L}, {Long.MAX_VALUE/1000000000L, 1000000000L}, {Long.MAX_VALUE/10000000000L, 10000000000L}, {Long.MAX_VALUE/100000000000L, 100000000000L}, {Long.MAX_VALUE/1000000000000L, 1000000000000L}, {Long.MAX_VALUE/100000000000000L, 10000000000000L}, }; 3162 3163 private static boolean compactLong(long val) { 3164 return (val != Long.MIN_VALUE); 3165 } 3166 3167 3171 private BigDecimal inflate() { 3172 if (intVal == null) 3173 intVal = BigInteger.valueOf(intCompact); 3174 return this; 3175 } 3176 3177 3190 private static void matchScale(BigDecimal [] val) { 3191 if (val[0].scale < val[1].scale) 3192 val[0] = val[0].setScale(val[1].scale); 3193 else if (val[1].scale < val[0].scale) 3194 val[1] = val[1].setScale(val[0].scale); 3195 } 3196 3197 3203 private synchronized void readObject(java.io.ObjectInputStream s) 3204 throws java.io.IOException , ClassNotFoundException { 3205 s.defaultReadObject(); 3207 if (intVal == null) { 3209 String message = "BigDecimal: null intVal in stream"; 3210 throw new java.io.StreamCorruptedException (message); 3211 } 3213 intCompact = INFLATED; 3216 } 3217 3218 3223 private void writeObject(java.io.ObjectOutputStream s) 3224 throws java.io.IOException { 3225 this.inflate(); 3227 3228 s.defaultWriteObject(); 3230 } 3231 3232 3254 private int digitLength() { 3255 if (intCompact != INFLATED && Math.abs(intCompact) <= Integer.MAX_VALUE) 3256 return intLength(Math.abs((int)intCompact)); 3257 if (signum() == 0) return 1; 3259 this.inflate(); 3260 BigInteger work = intVal; 3262 int digits = 0; for (;work.mag.length>1;) { 3264 work = work.divide(TENPOWERS[9]); 3267 digits += 9; 3268 if (work.signum() == 0) return digits; } 3271 digits += intLength(work.mag[0]); 3273 return digits; 3275 } 3276 3277 private static int[] ilogTable = { 3278 0, 3279 9, 3280 99, 3281 999, 3282 9999, 3283 99999, 3284 999999, 3285 9999999, 3286 99999999, 3287 999999999, 3288 Integer.MAX_VALUE}; 3289 3290 3295 private int intLength(int x) { 3296 int digits; 3297 if (x < 0) { return 10; 3299 } else { if (x <= 9) 3301 return 1; 3302 for(int i = -1; ; i++) { 3304 if (x <= ilogTable[i+1]) 3305 return i +1; 3306 } 3307 } 3308 } 3309 3310 3324 private BigDecimal stripZerosToMatchScale(long preferredScale) { 3325 boolean compact = (intCompact != INFLATED); 3326 this.inflate(); 3327 BigInteger qr[]; while ( intVal.abs().compareTo(BigInteger.TEN) >= 0 && 3329 scale > preferredScale) { 3330 if (intVal.testBit(0)) 3331 break; qr = intVal.divideAndRemainder(BigInteger.TEN); 3333 if (qr[1].signum() != 0) 3334 break; intVal=qr[0]; 3336 scale = checkScale((long)scale-1); if (precision > 0) precision--; 3339 } 3340 if (compact) 3341 intCompact = intVal.longValue(); 3342 return this; 3343 } 3344 3345 3357 private int checkScale(long val) { 3358 if ((int)val != val) { 3359 if ((this.intCompact != INFLATED && this.intCompact != 0) || 3360 (this.intVal != null && this.signum() != 0) || 3361 (this.intVal == null && this.intCompact == INFLATED) ) { 3362 if (val > Integer.MAX_VALUE) 3363 throw new ArithmeticException ("Underflow"); 3364 if (val < Integer.MIN_VALUE) 3365 throw new ArithmeticException ("Overflow"); 3366 } else { 3367 return (val > Integer.MAX_VALUE)?Integer.MAX_VALUE:Integer.MIN_VALUE; 3368 } 3369 } 3370 return (int)val; 3371 } 3372 3373 3382 private BigDecimal roundOp(MathContext mc) { 3383 BigDecimal rounded = doRound(mc); 3384 return rounded; 3385 } 3386 3387 3398 private void roundThis(MathContext mc) { 3399 BigDecimal rounded = doRound(mc); 3400 if (rounded == this) return; 3402 this.intVal = rounded.intVal; 3403 this.intCompact = rounded.intCompact; 3404 this.scale = rounded.scale; 3405 this.precision = rounded.precision; 3406 } 3407 3408 3421 private BigDecimal doRound(MathContext mc) { 3422 this.inflate(); 3423 if (precision == 0) { 3424 if (mc.roundingMax != null 3425 && intVal.compareTo(mc.roundingMax) < 0 3426 && intVal.compareTo(mc.roundingMin) > 0) 3427 return this; precision(); } 3430 int drop = precision - mc.precision; if (drop <= 0) return this; 3433 BigDecimal rounded = dropDigits(mc, drop); 3434 return rounded.doRound(mc); 3436 } 3437 3438 3457 private BigDecimal dropDigits(MathContext mc, int drop) { 3458 BigDecimal divisor = new BigDecimal (tenToThe(drop), 0); 3461 3462 BigDecimal rounded = this.divide(divisor, scale, 3464 mc.roundingMode.oldMode); 3465 rounded.scale = checkScale((long)rounded.scale - drop ); return rounded; 3467 } 3468 3469 private static int longCompareTo(long x, long y) { 3470 return (x < y) ? -1 : (x == y) ? 0 : 1; 3471 } 3472 3473 3476 private static void print(String name, BigDecimal bd) { 3477 System.err.format("%s:\tintCompact %d\tintVal %d\tscale %d\tprecision %d%n", 3478 name, 3479 bd.intCompact, 3480 bd.intVal, 3481 bd.scale, 3482 bd.precision); 3483 } 3484 3485 3501 private BigDecimal audit() { 3502 if (precision > 0) { 3504 if (precision != digitLength()) { 3505 print("audit", this); 3506 throw new AssertionError ("precision mismatch"); 3507 } 3508 } 3509 3510 if (intCompact == INFLATED) { 3511 if (intVal == null) { 3512 print("audit", this); 3513 throw new AssertionError ("null intVal"); 3514 } 3515 } else { 3516 if (intVal != null) { 3517 long val = intVal.longValue(); 3518 if (val != intCompact) { 3519 print("audit", this); 3520 throw new AssertionError ("Inconsistent state, intCompact=" + 3521 intCompact + "\t intVal=" + val); 3522 } 3523 } 3524 } 3525 return this; 3526 } 3527} 3528 | Popular Tags |