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 trueif 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, <code>'&#92;u0020'</code>,
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 }
327