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 (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:
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:
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: }