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