1 | /* java.math.BigDecimal -- Arbitrary precision decimals.
|
---|
2 | Copyright (C) 1999, 2000, 2001 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 |
|
---|
63 | public BigDecimal (BigInteger num)
|
---|
64 | {
|
---|
65 | this (num, 0);
|
---|
66 | }
|
---|
67 |
|
---|
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 |
|
---|
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 |
|
---|
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 |
|
---|
209 | public static BigDecimal valueOf (long val)
|
---|
210 | {
|
---|
211 | return valueOf (val, 0);
|
---|
212 | }
|
---|
213 |
|
---|
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 |
|
---|
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 |
|
---|
244 | public BigDecimal subtract (BigDecimal val)
|
---|
245 | {
|
---|
246 | return this.add(val.negate());
|
---|
247 | }
|
---|
248 |
|
---|
249 | public BigDecimal multiply (BigDecimal val)
|
---|
250 | {
|
---|
251 | return new BigDecimal (intVal.multiply (val.intVal), scale + val.scale);
|
---|
252 | }
|
---|
253 |
|
---|
254 | public BigDecimal divide (BigDecimal val, int roundingMode)
|
---|
255 | throws ArithmeticException, IllegalArgumentException
|
---|
256 | {
|
---|
257 | return divide (val, scale, roundingMode);
|
---|
258 | }
|
---|
259 |
|
---|
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 + 1 - (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 | // System.out.println("int: " + parts[0]);
|
---|
289 | // System.out.println("rem: " + parts[1]);
|
---|
290 |
|
---|
291 | int roundDigit = parts[0].mod (BigInteger.valueOf (10)).intValue ();
|
---|
292 | BigInteger unrounded = parts[0].divide (BigInteger.valueOf (10));
|
---|
293 |
|
---|
294 | if (roundDigit == 0 && parts[1].signum () == 0) // no rounding necessary
|
---|
295 | return new BigDecimal (unrounded, newScale);
|
---|
296 |
|
---|
297 | int sign = unrounded.signum ();
|
---|
298 |
|
---|
299 | switch (roundingMode)
|
---|
300 | {
|
---|
301 | case ROUND_UNNECESSARY:
|
---|
302 | throw new ArithmeticException ("newScale is not large enough");
|
---|
303 | case ROUND_CEILING:
|
---|
304 | roundingMode = (sign == 1) ? ROUND_UP : ROUND_DOWN;
|
---|
305 | break;
|
---|
306 | case ROUND_FLOOR:
|
---|
307 | roundingMode = (sign == 1) ? ROUND_DOWN : ROUND_UP;
|
---|
308 | break;
|
---|
309 | case ROUND_HALF_UP:
|
---|
310 | roundingMode = (roundDigit >= 5) ? ROUND_UP : ROUND_DOWN;
|
---|
311 | break;
|
---|
312 | case ROUND_HALF_DOWN:
|
---|
313 | roundingMode = (roundDigit > 5) ? ROUND_UP : ROUND_DOWN;
|
---|
314 | break;
|
---|
315 | case ROUND_HALF_EVEN:
|
---|
316 | if (roundDigit < 5)
|
---|
317 | roundingMode = ROUND_DOWN;
|
---|
318 | else
|
---|
319 | {
|
---|
320 | int rightmost =
|
---|
321 | unrounded.mod (BigInteger.valueOf (10)).intValue ();
|
---|
322 | if (rightmost % 2 == 1) // odd, then ROUND_HALF_UP
|
---|
323 | roundingMode = ROUND_UP;
|
---|
324 | else // even, then ROUND_HALF_DOWN
|
---|
325 | roundingMode = (roundDigit > 5) ? ROUND_UP : ROUND_DOWN;
|
---|
326 | }
|
---|
327 | break;
|
---|
328 | }
|
---|
329 |
|
---|
330 | if (roundingMode == ROUND_UP)
|
---|
331 | return new BigDecimal (unrounded.add (BigInteger.valueOf (1)), newScale);
|
---|
332 |
|
---|
333 | // roundingMode == ROUND_DOWN
|
---|
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 | // quotients are the same, so compare remainders
|
---|
352 |
|
---|
353 | // remove trailing zeros
|
---|
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 | // again...
|
---|
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 | // and compare them
|
---|
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 | }
|
---|