1:
37:
38: package ;
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:
50: public static final BigDecimal ZERO =
51: new BigDecimal (BigInteger.valueOf (0), 0);
52:
53:
57: public static final BigDecimal ONE =
58: new BigDecimal (BigInteger.valueOf (1), 0);
59:
60:
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:
94:
95:
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:
107: exponent -= denormal ? 1022 : 1023;
108:
109:
110: exponent -= mantissaBits;
111:
112: if (! denormal)
113: mantissa |= (1L << mantissaBits);
114:
115:
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:
126:
127:
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:
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:
245:
246:
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)
284: return newScale == 0 ? ZERO : new BigDecimal (ZERO.intVal, newScale);
285:
286:
287: BigInteger valIntVal = val.intVal;
288: int power = newScale - (scale - val.scale);
289: if (power < 0)
290: {
291:
292:
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)
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:
317:
318:
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))
338: roundingMode = ROUND_UP;
339: else
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:
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:
367:
368:
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:
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: }