1 /* java.math.BigDecimal -- Arbitrary precision decimals.
2    Copyright (C) 1999, 2000, 2001, 2003 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 
BigDecimal(BigInteger num)63   public BigDecimal (BigInteger num)
64   {
65     this (num, 0);
66   }
67 
BigDecimal(BigInteger num, int scale)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 
BigDecimal(double num)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 
BigDecimal(String num)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 
valueOf(long val)209   public static BigDecimal valueOf (long val)
210   {
211     return valueOf (val, 0);
212   }
213 
valueOf(long val, int scale)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 
add(BigDecimal val)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 
subtract(BigDecimal val)244   public BigDecimal subtract (BigDecimal val)
245   {
246     return this.add(val.negate());
247   }
248 
multiply(BigDecimal val)249   public BigDecimal multiply (BigDecimal val)
250   {
251     return new BigDecimal (intVal.multiply (val.intVal), scale + val.scale);
252   }
253 
divide(BigDecimal val, int roundingMode)254   public BigDecimal divide (BigDecimal val, int roundingMode)
255     throws ArithmeticException, IllegalArgumentException
256   {
257     return divide (val, scale, roundingMode);
258   }
259 
divide(BigDecimal val, int newScale, int roundingMode)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 - (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 
289     BigInteger unrounded = parts[0];
290     if (parts[1].signum () == 0) // no remainder, no rounding necessary
291       return new BigDecimal (unrounded, newScale);
292 
293     if (roundingMode == ROUND_UNNECESSARY)
294       throw new ArithmeticException ("newScale is not large enough");
295 
296     int sign = intVal.signum () * valIntVal.signum ();
297 
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
303       {
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);
311 
312 	switch(roundingMode)
313 	  {
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;
330 	  }
331       }
332 
333     if (roundingMode == ROUND_UP)
334       unrounded = unrounded.add (BigInteger.valueOf (sign > 0 ? 1 : -1));
335 
336     // roundingMode == ROUND_DOWN
337     return new BigDecimal (unrounded, newScale);
338   }
339 
340   public int compareTo (BigDecimal val)
341   {
342     if (scale == val.scale)
343       return intVal.compareTo (val.intVal);
344 
345     BigInteger thisParts[] =
346       intVal.divideAndRemainder (BigInteger.valueOf (10).pow (scale));
347     BigInteger valParts[] =
348       val.intVal.divideAndRemainder (BigInteger.valueOf (10).pow (val.scale));
349 
350     int compare;
351     if ((compare = thisParts[0].compareTo (valParts[0])) != 0)
352       return compare;
353 
354     // quotients are the same, so compare remainders
355 
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));
366 
367     // and compare them
368     return thisParts[1].compareTo (valParts[1]);
369   }
370 
371   public int compareTo (Object val)
372   {
373     return(compareTo((BigDecimal)val));
374   }
375 
376   public boolean equals (Object o)
377   {
378     return (o instanceof BigDecimal
379 	    && scale == ((BigDecimal) o).scale
380 	    && compareTo ((BigDecimal) o) == 0);
381   }
382 
383   public int hashCode()
384   {
385     return intValue() ^ scale;
386   }
387 
388   public BigDecimal max (BigDecimal val)
389   {
390     switch (compareTo (val))
391       {
392       case 1:
393 	return this;
394       default:
395 	return val;
396       }
397   }
398 
399   public BigDecimal min (BigDecimal val)
400   {
401     switch (compareTo (val))
402       {
403       case -1:
404 	return this;
405       default:
406 	return val;
407       }
408   }
409 
410   public BigDecimal movePointLeft (int n)
411   {
412     return (n < 0) ? movePointRight (-n) : new BigDecimal (intVal, scale + n);
413   }
414 
415   public BigDecimal movePointRight (int n)
416   {
417     if (n < 0)
418       return movePointLeft (-n);
419 
420     if (scale >= n)
421       return new BigDecimal (intVal, scale - n);
422 
423     return new BigDecimal (intVal.multiply
424 			   (BigInteger.valueOf (10).pow (n - scale)), 0);
425   }
426 
427   public int signum ()
428   {
429     return intVal.signum ();
430   }
431 
432   public int scale ()
433   {
434     return scale;
435   }
436 
437   public BigInteger unscaledValue()
438   {
439     return intVal;
440   }
441 
442   public BigDecimal abs ()
443   {
444     return new BigDecimal (intVal.abs (), scale);
445   }
446 
447   public BigDecimal negate ()
448   {
449     return new BigDecimal (intVal.negate (), scale);
450   }
451 
452   public String toString ()
453   {
454     String bigStr = intVal.toString();
455     if (scale == 0)
456       return bigStr;
457 
458     boolean negative = (bigStr.charAt(0) == '-');
459 
460     int point = bigStr.length() - scale - (negative ? 1 : 0);
461 
462     StringBuffer sb = new StringBuffer(bigStr.length() + 2 +
463 				       (point <= 0 ? (-point + 1) : 0));
464     if (point <= 0)
465       {
466         if (negative)
467           sb.append('-');
468         sb.append('0').append('.');
469         while (point < 0)
470           {
471             sb.append('0');
472             point++;
473           }
474         sb.append(bigStr.substring(negative ? 1 : 0));
475       }
476     else
477       {
478 	sb.append(bigStr);
479 	sb.insert(point + (negative ? 1 : 0), '.');
480       }
481     return sb.toString();
482   }
483 
484   public BigInteger toBigInteger ()
485   {
486     return scale == 0 ? intVal :
487       intVal.divide (BigInteger.valueOf (10).pow (scale));
488   }
489 
490   public int intValue ()
491   {
492     return toBigInteger ().intValue ();
493   }
494 
495   public long longValue ()
496   {
497     return toBigInteger().longValue();
498   }
499 
500   public float floatValue()
501   {
502     return Float.valueOf(toString()).floatValue();
503   }
504 
505   public double doubleValue()
506   {
507     return Double.valueOf(toString()).doubleValue();
508   }
509 
510   public BigDecimal setScale (int scale) throws ArithmeticException
511   {
512     return setScale (scale, ROUND_UNNECESSARY);
513   }
514 
515   public BigDecimal setScale (int scale, int roundingMode)
516     throws ArithmeticException, IllegalArgumentException
517   {
518     return divide (ONE, scale, roundingMode);
519   }
520 }
521