2003-12-26 Guilhem Lavaux <guilhem@kaffe.org>
[official-gcc.git] / libjava / java / math / BigDecimal.java
blobf9965add4c1643f6fd53b9ef9636e929c034738e
1 /* java.math.BigDecimal -- Arbitrary precision decimals.
2 Copyright (C) 1999, 2000, 2001, 2003 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
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.
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.
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.
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.
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. */
38 package java.math;
40 import java.math.BigInteger;
42 public class BigDecimal extends Number implements Comparable
44 private BigInteger intVal;
45 private int scale;
46 private static final long serialVersionUID = 6108874887143696463L;
48 private final static BigDecimal ZERO =
49 new BigDecimal (BigInteger.valueOf (0), 0);
51 private final static BigDecimal ONE =
52 new BigDecimal (BigInteger.valueOf (1), 0);
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;
63 public BigDecimal (BigInteger num)
65 this (num, 0);
68 public BigDecimal (BigInteger num, int scale) throws NumberFormatException
70 if (scale < 0)
71 throw new NumberFormatException ("scale of " + scale + " is < 0");
72 this.intVal = num;
73 this.scale = scale;
76 public BigDecimal (double num) throws NumberFormatException
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.
84 final int mantissaBits = 52;
85 final int exponentBits = 11;
86 final long mantMask = (1L << mantissaBits) - 1;
87 final long expMask = (1L << exponentBits) - 1;
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);
102 // Shave off factors of 10.
103 while (exponent < 0 && (mantissa & 1) == 0)
105 ++exponent;
106 mantissa >>= 1;
109 intVal = BigInteger.valueOf (bits < 0 ? - mantissa : mantissa);
110 if (exponent < 0)
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);
119 else
121 intVal = intVal.shiftLeft ((int) exponent);
122 scale = 0;
126 public BigDecimal (String num) throws NumberFormatException
128 int len = num.length();
129 int start = 0, point = 0;
130 int dot = -1;
131 boolean negative = false;
132 if (num.charAt(0) == '+')
134 ++start;
135 ++point;
137 else if (num.charAt(0) == '-')
139 ++start;
140 ++point;
141 negative = true;
144 while (point < len)
146 char c = num.charAt (point);
147 if (c == '.')
149 if (dot >= 0)
150 throw new NumberFormatException ("multiple `.'s in number");
151 dot = point;
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;
160 String val;
161 if (dot >= 0)
163 val = num.substring (start, dot) + num.substring (dot + 1, point);
164 scale = point - 1 - dot;
166 else
168 val = num.substring (start, point);
169 scale = 0;
171 if (val.length () == 0)
172 throw new NumberFormatException ("no digits seen");
174 if (negative)
175 val = "-" + val;
176 intVal = new BigInteger (val);
178 // Now parse exponent.
179 if (point < len)
181 point++;
182 if (num.charAt(point) == '+')
183 point++;
185 if (point >= len )
186 throw new NumberFormatException ("no exponent following e or E");
188 try
190 int exp = Integer.parseInt (num.substring (point));
191 exp -= scale;
192 if (signum () == 0)
193 scale = 0;
194 else if (exp > 0)
196 intVal = intVal.multiply (BigInteger.valueOf (10).pow (exp));
197 scale = 0;
199 else
200 scale = - exp;
202 catch (NumberFormatException ex)
204 throw new NumberFormatException ("malformed exponent");
209 public static BigDecimal valueOf (long val)
211 return valueOf (val, 0);
214 public static BigDecimal valueOf (long val, int scale)
215 throws NumberFormatException
217 if ((scale == 0) && ((int)val == val))
218 switch ((int) val)
220 case 0:
221 return ZERO;
222 case 1:
223 return ONE;
226 return new BigDecimal (BigInteger.valueOf (val), scale);
229 public BigDecimal add (BigDecimal val)
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));
241 return new BigDecimal (op1.add (op2), Math.max (scale, val.scale));
244 public BigDecimal subtract (BigDecimal val)
246 return this.add(val.negate());
249 public BigDecimal multiply (BigDecimal val)
251 return new BigDecimal (intVal.multiply (val.intVal), scale + val.scale);
254 public BigDecimal divide (BigDecimal val, int roundingMode)
255 throws ArithmeticException, IllegalArgumentException
257 return divide (val, scale, roundingMode);
260 public BigDecimal divide(BigDecimal val, int newScale, int roundingMode)
261 throws ArithmeticException, IllegalArgumentException
263 if (roundingMode < 0 || roundingMode > 7)
264 throw
265 new IllegalArgumentException("illegal rounding mode: " + roundingMode);
267 if (newScale < 0)
268 throw new ArithmeticException ("scale is negative: " + newScale);
270 if (intVal.signum () == 0) // handle special case of 0.0/0.0
271 return newScale == 0 ? ZERO : new BigDecimal (ZERO.intVal, newScale);
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)
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;
285 BigInteger dividend = intVal.multiply (BigInteger.valueOf (10).pow (power));
287 BigInteger parts[] = dividend.divideAndRemainder (valIntVal);
289 BigInteger unrounded = parts[0];
290 if (parts[1].signum () == 0) // no remainder, no rounding necessary
291 return new BigDecimal (unrounded, newScale);
293 if (roundingMode == ROUND_UNNECESSARY)
294 throw new ArithmeticException ("newScale is not large enough");
296 int sign = intVal.signum () * valIntVal.signum ();
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
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);
312 switch(roundingMode)
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;
333 if (roundingMode == ROUND_UP)
334 unrounded = unrounded.add (BigInteger.valueOf (sign > 0 ? 1 : -1));
336 // roundingMode == ROUND_DOWN
337 return new BigDecimal (unrounded, newScale);
340 public int compareTo (BigDecimal val)
342 if (scale == val.scale)
343 return intVal.compareTo (val.intVal);
345 BigInteger thisParts[] =
346 intVal.divideAndRemainder (BigInteger.valueOf (10).pow (scale));
347 BigInteger valParts[] =
348 val.intVal.divideAndRemainder (BigInteger.valueOf (10).pow (val.scale));
350 int compare;
351 if ((compare = thisParts[0].compareTo (valParts[0])) != 0)
352 return compare;
354 // quotients are the same, so compare remainders
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));
367 // and compare them
368 return thisParts[1].compareTo (valParts[1]);
371 public int compareTo (Object val)
373 return(compareTo((BigDecimal)val));
376 public boolean equals (Object o)
378 return (o instanceof BigDecimal
379 && scale == ((BigDecimal) o).scale
380 && compareTo ((BigDecimal) o) == 0);
383 public int hashCode()
385 return intValue() ^ scale;
388 public BigDecimal max (BigDecimal val)
390 switch (compareTo (val))
392 case 1:
393 return this;
394 default:
395 return val;
399 public BigDecimal min (BigDecimal val)
401 switch (compareTo (val))
403 case -1:
404 return this;
405 default:
406 return val;
410 public BigDecimal movePointLeft (int n)
412 return (n < 0) ? movePointRight (-n) : new BigDecimal (intVal, scale + n);
415 public BigDecimal movePointRight (int n)
417 if (n < 0)
418 return movePointLeft (-n);
420 if (scale >= n)
421 return new BigDecimal (intVal, scale - n);
423 return new BigDecimal (intVal.multiply
424 (BigInteger.valueOf (10).pow (n - scale)), 0);
427 public int signum ()
429 return intVal.signum ();
432 public int scale ()
434 return scale;
437 public BigInteger unscaledValue()
439 return intVal;
442 public BigDecimal abs ()
444 return new BigDecimal (intVal.abs (), scale);
447 public BigDecimal negate ()
449 return new BigDecimal (intVal.negate (), scale);
452 public String toString ()
454 String bigStr = intVal.toString();
455 if (scale == 0)
456 return bigStr;
458 boolean negative = (bigStr.charAt(0) == '-');
460 int point = bigStr.length() - scale - (negative ? 1 : 0);
462 StringBuffer sb = new StringBuffer(bigStr.length() + 2 +
463 (point <= 0 ? (-point + 1) : 0));
464 if (point <= 0)
466 if (negative)
467 sb.append('-');
468 sb.append('0').append('.');
469 while (point < 0)
471 sb.append('0');
472 point++;
474 sb.append(bigStr.substring(negative ? 1 : 0));
476 else
478 sb.append(bigStr);
479 sb.insert(point + (negative ? 1 : 0), '.');
481 return sb.toString();
484 public BigInteger toBigInteger ()
486 return scale == 0 ? intVal :
487 intVal.divide (BigInteger.valueOf (10).pow (scale));
490 public int intValue ()
492 return toBigInteger ().intValue ();
495 public long longValue ()
497 return toBigInteger().longValue();
500 public float floatValue()
502 return Float.valueOf(toString()).floatValue();
505 public double doubleValue()
507 return Double.valueOf(toString()).doubleValue();
510 public BigDecimal setScale (int scale) throws ArithmeticException
512 return setScale (scale, ROUND_UNNECESSARY);
515 public BigDecimal setScale (int scale, int roundingMode)
516 throws ArithmeticException, IllegalArgumentException
518 return divide (ONE, scale, roundingMode);