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