View Javadoc
1   /*
2    * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  
26  /*
27   * Portions Copyright IBM Corporation, 1997, 2001. All Rights Reserved.
28   */
29  
30  package java.math;
31  import java.io.*;
32  
33  /**
34   * Immutable objects which encapsulate the context settings which
35   * describe certain rules for numerical operators, such as those
36   * implemented by the {@link BigDecimal} class.
37   *
38   * <p>The base-independent settings are:
39   * <ol>
40   * <li>{@code precision}:
41   * the number of digits to be used for an operation; results are
42   * rounded to this precision
43   *
44   * <li>{@code roundingMode}:
45   * a {@link RoundingMode} object which specifies the algorithm to be
46   * used for rounding.
47   * </ol>
48   *
49   * @see     BigDecimal
50   * @see     RoundingMode
51   * @author  Mike Cowlishaw
52   * @author  Joseph D. Darcy
53   * @since 1.5
54   */
55  
56  public final class MathContext implements Serializable {
57  
58      /* ----- Constants ----- */
59  
60      // defaults for constructors
61      private static final int DEFAULT_DIGITS = 9;
62      private static final RoundingMode DEFAULT_ROUNDINGMODE = RoundingMode.HALF_UP;
63      // Smallest values for digits (Maximum is Integer.MAX_VALUE)
64      private static final int MIN_DIGITS = 0;
65  
66      // Serialization version
67      private static final long serialVersionUID = 5579720004786848255L;
68  
69      /* ----- Public Properties ----- */
70      /**
71       *  A {@code MathContext} object whose settings have the values
72       *  required for unlimited precision arithmetic.
73       *  The values of the settings are:
74       *  <code>
75       *  precision=0 roundingMode=HALF_UP
76       *  </code>
77       */
78      public static final MathContext UNLIMITED =
79          new MathContext(0, RoundingMode.HALF_UP);
80  
81      /**
82       *  A {@code MathContext} object with a precision setting
83       *  matching the IEEE 754R Decimal32 format, 7 digits, and a
84       *  rounding mode of {@link RoundingMode#HALF_EVEN HALF_EVEN}, the
85       *  IEEE 754R default.
86       */
87      public static final MathContext DECIMAL32 =
88          new MathContext(7, RoundingMode.HALF_EVEN);
89  
90      /**
91       *  A {@code MathContext} object with a precision setting
92       *  matching the IEEE 754R Decimal64 format, 16 digits, and a
93       *  rounding mode of {@link RoundingMode#HALF_EVEN HALF_EVEN}, the
94       *  IEEE 754R default.
95       */
96      public static final MathContext DECIMAL64 =
97          new MathContext(16, RoundingMode.HALF_EVEN);
98  
99      /**
100      *  A {@code MathContext} object with a precision setting
101      *  matching the IEEE 754R Decimal128 format, 34 digits, and a
102      *  rounding mode of {@link RoundingMode#HALF_EVEN HALF_EVEN}, the
103      *  IEEE 754R default.
104      */
105     public static final MathContext DECIMAL128 =
106         new MathContext(34, RoundingMode.HALF_EVEN);
107 
108     /* ----- Shared Properties ----- */
109     /**
110      * The number of digits to be used for an operation.  A value of 0
111      * indicates that unlimited precision (as many digits as are
112      * required) will be used.  Note that leading zeros (in the
113      * coefficient of a number) are never significant.
114      *
115      * <p>{@code precision} will always be non-negative.
116      *
117      * @serial
118      */
119     final int precision;
120 
121     /**
122      * The rounding algorithm to be used for an operation.
123      *
124      * @see RoundingMode
125      * @serial
126      */
127     final RoundingMode roundingMode;
128 
129     /* ----- Constructors ----- */
130 
131     /**
132      * Constructs a new {@code MathContext} with the specified
133      * precision and the {@link RoundingMode#HALF_UP HALF_UP} rounding
134      * mode.
135      *
136      * @param setPrecision The non-negative {@code int} precision setting.
137      * @throws IllegalArgumentException if the {@code setPrecision} parameter is less
138      *         than zero.
139      */
140     public MathContext(int setPrecision) {
141         this(setPrecision, DEFAULT_ROUNDINGMODE);
142         return;
143     }
144 
145     /**
146      * Constructs a new {@code MathContext} with a specified
147      * precision and rounding mode.
148      *
149      * @param setPrecision The non-negative {@code int} precision setting.
150      * @param setRoundingMode The rounding mode to use.
151      * @throws IllegalArgumentException if the {@code setPrecision} parameter is less
152      *         than zero.
153      * @throws NullPointerException if the rounding mode argument is {@code null}
154      */
155     public MathContext(int setPrecision,
156                        RoundingMode setRoundingMode) {
157         if (setPrecision < MIN_DIGITS)
158             throw new IllegalArgumentException("Digits < 0");
159         if (setRoundingMode == null)
160             throw new NullPointerException("null RoundingMode");
161 
162         precision = setPrecision;
163         roundingMode = setRoundingMode;
164         return;
165     }
166 
167     /**
168      * Constructs a new {@code MathContext} from a string.
169      *
170      * The string must be in the same format as that produced by the
171      * {@link #toString} method.
172      *
173      * <p>An {@code IllegalArgumentException} is thrown if the precision
174      * section of the string is out of range ({@code < 0}) or the string is
175      * not in the format created by the {@link #toString} method.
176      *
177      * @param val The string to be parsed
178      * @throws IllegalArgumentException if the precision section is out of range
179      * or of incorrect format
180      * @throws NullPointerException if the argument is {@code null}
181      */
182     public MathContext(String val) {
183         boolean bad = false;
184         int setPrecision;
185         if (val == null)
186             throw new NullPointerException("null String");
187         try { // any error here is a string format problem
188             if (!val.startsWith("precision=")) throw new RuntimeException();
189             int fence = val.indexOf(' ');    // could be -1
190             int off = 10;                     // where value starts
191             setPrecision = Integer.parseInt(val.substring(10, fence));
192 
193             if (!val.startsWith("roundingMode=", fence+1))
194                 throw new RuntimeException();
195             off = fence + 1 + 13;
196             String str = val.substring(off, val.length());
197             roundingMode = RoundingMode.valueOf(str);
198         } catch (RuntimeException re) {
199             throw new IllegalArgumentException("bad string format");
200         }
201 
202         if (setPrecision < MIN_DIGITS)
203             throw new IllegalArgumentException("Digits < 0");
204         // the other parameters cannot be invalid if we got here
205         precision = setPrecision;
206     }
207 
208     /**
209      * Returns the {@code precision} setting.
210      * This value is always non-negative.
211      *
212      * @return an {@code int} which is the value of the {@code precision}
213      *         setting
214      */
215     public int getPrecision() {
216         return precision;
217     }
218 
219     /**
220      * Returns the roundingMode setting.
221      * This will be one of
222      * {@link  RoundingMode#CEILING},
223      * {@link  RoundingMode#DOWN},
224      * {@link  RoundingMode#FLOOR},
225      * {@link  RoundingMode#HALF_DOWN},
226      * {@link  RoundingMode#HALF_EVEN},
227      * {@link  RoundingMode#HALF_UP},
228      * {@link  RoundingMode#UNNECESSARY}, or
229      * {@link  RoundingMode#UP}.
230      *
231      * @return a {@code RoundingMode} object which is the value of the
232      *         {@code roundingMode} setting
233      */
234 
235     public RoundingMode getRoundingMode() {
236         return roundingMode;
237     }
238 
239     /**
240      * Compares this {@code MathContext} with the specified
241      * {@code Object} for equality.
242      *
243      * @param  x {@code Object} to which this {@code MathContext} is to
244      *         be compared.
245      * @return {@code true} if and only if the specified {@code Object} is
246      *         a {@code MathContext} object which has exactly the same
247      *         settings as this object
248      */
249     public boolean equals(Object x){
250         MathContext mc;
251         if (!(x instanceof MathContext))
252             return false;
253         mc = (MathContext) x;
254         return mc.precision == this.precision
255             && mc.roundingMode == this.roundingMode; // no need for .equals()
256     }
257 
258     /**
259      * Returns the hash code for this {@code MathContext}.
260      *
261      * @return hash code for this {@code MathContext}
262      */
263     public int hashCode() {
264         return this.precision + roundingMode.hashCode() * 59;
265     }
266 
267     /**
268      * Returns the string representation of this {@code MathContext}.
269      * The {@code String} returned represents the settings of the
270      * {@code MathContext} object as two space-delimited words
271      * (separated by a single space character, <tt>'&#92;u0020'</tt>,
272      * and with no leading or trailing white space), as follows:
273      * <ol>
274      * <li>
275      * The string {@code "precision="}, immediately followed
276      * by the value of the precision setting as a numeric string as if
277      * generated by the {@link Integer#toString(int) Integer.toString}
278      * method.
279      *
280      * <li>
281      * The string {@code "roundingMode="}, immediately
282      * followed by the value of the {@code roundingMode} setting as a
283      * word.  This word will be the same as the name of the
284      * corresponding public constant in the {@link RoundingMode}
285      * enum.
286      * </ol>
287      * <p>
288      * For example:
289      * <pre>
290      * precision=9 roundingMode=HALF_UP
291      * </pre>
292      *
293      * Additional words may be appended to the result of
294      * {@code toString} in the future if more properties are added to
295      * this class.
296      *
297      * @return a {@code String} representing the context settings
298      */
299     public java.lang.String toString() {
300         return "precision=" +           precision + " " +
301                "roundingMode=" +        roundingMode.toString();
302     }
303 
304     // Private methods
305 
306     /**
307      * Reconstitute the {@code MathContext} instance from a stream (that is,
308      * deserialize it).
309      *
310      * @param s the stream being read.
311      */
312     private void readObject(java.io.ObjectInputStream s)
313         throws java.io.IOException, ClassNotFoundException {
314         s.defaultReadObject();     // read in all fields
315         // validate possibly bad fields
316         if (precision < MIN_DIGITS) {
317             String message = "MathContext: invalid digits in stream";
318             throw new java.io.StreamCorruptedException(message);
319         }
320         if (roundingMode == null) {
321             String message = "MathContext: null roundingMode in stream";
322             throw new java.io.StreamCorruptedException(message);
323         }
324     }
325 
326 }