1 /*
2 * Portions Copyright 2003-2007 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any 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 /**
130 * Lookaside for the rounding points (the numbers which determine
131 * whether the coefficient of a number will require rounding).
132 * These will be present if {@code precision > 0} and
133 * {@code precision <= MAX_LOOKASIDE}. In this case they will share the
134 * {@code BigInteger int[]} array. Note that the transients
135 * cannot be {@code final} because they are reconstructed on
136 * deserialization.
137 */
138 transient BigInteger roundingMax = null;
139 transient BigInteger roundingMin = null;
140 private static final int MAX_LOOKASIDE = 1000;
141
142 /* ----- Constructors ----- */
143
144 /**
145 * Constructs a new {@code MathContext} with the specified
146 * precision and the {@link RoundingMode#HALF_UP HALF_UP} rounding
147 * mode.
148 *
149 * @param setPrecision The non-negative {@code int} precision setting.
150 * @throws IllegalArgumentException if the {@code setPrecision} parameter is less
151 * than zero.
152 */
153 public MathContext(int setPrecision) {
154 this(setPrecision, DEFAULT_ROUNDINGMODE);
155 return;
156 }
157
158 /**
159 * Constructs a new {@code MathContext} with a specified
160 * precision and rounding mode.
161 *
162 * @param setPrecision The non-negative {@code int} precision setting.
163 * @param setRoundingMode The rounding mode to use.
164 * @throws IllegalArgumentException if the {@code setPrecision} parameter is less
165 * than zero.
166 * @throws NullPointerException if the rounding mode argument is {@code null}
167 */
168 public MathContext(int setPrecision,
169 RoundingMode setRoundingMode) {
170 if (setPrecision < MIN_DIGITS)
171 throw new IllegalArgumentException("Digits < 0");
172 if (setRoundingMode == null)
173 throw new NullPointerException("null RoundingMode");
174
175 precision = setPrecision;
176 if (precision > 0 && precision <= MAX_LOOKASIDE) {
177 roundingMax = BigInteger.TEN.pow(precision);
178 roundingMin = roundingMax.negate();
179 }
180
181 roundingMode = setRoundingMode;
182 return;
183 }
184
185 /**
186 * Constructs a new {@code MathContext} from a string.
187 *
188 * The string must be in the same format as that produced by the
189 * {@link #toString} method.
190 *
191 * <p>An {@code IllegalArgumentException} is thrown if the precision
192 * section of the string is out of range ({@code < 0}) or the string is
193 * not in the format created by the {@link #toString} method.
194 *
195 * @param val The string to be parsed
196 * @throws IllegalArgumentException if the precision section is out of range
197 * or of incorrect format
198 * @throws NullPointerException if the argument is {@code null}
199 */
200 public MathContext(String val) {
201 boolean bad = false;
202 int setPrecision;
203 if (val == null)
204 throw new NullPointerException("null String");
205 try { // any error here is a string format problem
206 if (!val.startsWith("precision=")) throw new RuntimeException();
207 int fence = val.indexOf(' '); // could be -1
208 int off = 10; // where value starts
209 setPrecision = Integer.parseInt(val.substring(10, fence));
210
211 if (!val.startsWith("roundingMode=", fence+1))
212 throw new RuntimeException();
213 off = fence + 1 + 13;
214 String str = val.substring(off, val.length());
215 roundingMode = RoundingMode.valueOf(str);
216 } catch (RuntimeException re) {
217 throw new IllegalArgumentException("bad string format");
218 }
219
220 if (setPrecision < MIN_DIGITS)
221 throw new IllegalArgumentException("Digits < 0");
222 // the other parameters cannot be invalid if we got here
223 precision = setPrecision;
224 if (precision > 0 && precision <= MAX_LOOKASIDE) {
225 roundingMax = BigInteger.TEN.pow(precision);
226 roundingMin = roundingMax.negate();
227 }
228 }
229
230 /**
231 * Returns the {@code precision} setting.
232 * This value is always non-negative.
233 *
234 * @return an {@code int} which is the value of the {@code precision}
235 * setting
236 */
237 public int getPrecision() {
238 return precision;
239 }
240
241 /**
242 * Returns the roundingMode setting.
243 * This will be one of
244 * {@link RoundingMode#CEILING},
245 * {@link RoundingMode#DOWN},
246 * {@link RoundingMode#FLOOR},
247 * {@link RoundingMode#HALF_DOWN},
248 * {@link RoundingMode#HALF_EVEN},
249 * {@link RoundingMode#HALF_UP},
250 * {@link RoundingMode#UNNECESSARY}, or
251 * {@link RoundingMode#UP}.
252 *
253 * @return a {@code RoundingMode} object which is the value of the
254 * {@code roundingMode} setting
255 */
256
257 public RoundingMode getRoundingMode() {
258 return roundingMode;
259 }
260
261 /**
262 * Compares this {@code MathContext} with the specified
263 * {@code Object} for equality.
264 *
265 * @param x {@code Object} to which this {@code MathContext} is to
266 * be compared.
267 * @return {@code true} if and only if the specified {@code Object} is
268 * a {@code MathContext} object which has exactly the same
269 * settings as this object
270 */
271 public boolean equals(Object x){
272 MathContext mc;
273 if (!(x instanceof MathContext))
274 return false;
275 mc = (MathContext) x;
276 return mc.precision == this.precision
277 && mc.roundingMode == this.roundingMode; // no need for .equals()
278 }
279
280 /**
281 * Returns the hash code for this {@code MathContext}.
282 *
283 * @return hash code for this {@code MathContext}
284 */
285 public int hashCode() {
286 return this.precision + roundingMode.hashCode() * 59;
287 }
288
289 /**
290 * Returns the string representation of this {@code MathContext}.
291 * The {@code String} returned represents the settings of the
292 * {@code MathContext} object as two space-delimited words
293 * (separated by a single space character, <tt>'\u0020'</tt>,
294 * and with no leading or trailing white space), as follows:
295 * <ol>
296 * <li>
297 * The string {@code "precision="}, immediately followed
298 * by the value of the precision setting as a numeric string as if
299 * generated by the {@link Integer#toString(int) Integer.toString}
300 * method.
301 *
302 * <li>
303 * The string {@code "roundingMode="}, immediately
304 * followed by the value of the {@code roundingMode} setting as a
305 * word. This word will be the same as the name of the
306 * corresponding public constant in the {@link RoundingMode}
307 * enum.
308 * </ol>
309 * <p>
310 * For example:
311 * <pre>
312 * precision=9 roundingMode=HALF_UP
313 * </pre>
314 *
315 * Additional words may be appended to the result of
316 * {@code toString} in the future if more properties are added to
317 * this class.
318 *
319 * @return a {@code String} representing the context settings
320 */
321 public java.lang.String toString() {
322 return "precision=" + precision + " " +
323 "roundingMode=" + roundingMode.toString();
324 }
325
326 // Private methods
327
328 /**
329 * Reconstitute the {@code MathContext} instance from a stream (that is,
330 * deserialize it).
331 *
332 * @param s the stream being read.
333 */
334 private void readObject(java.io.ObjectInputStream s)
335 throws java.io.IOException, ClassNotFoundException {
336 s.defaultReadObject(); // read in all fields
337 // validate possibly bad fields
338 if (precision < MIN_DIGITS) {
339 String message = "MathContext: invalid digits in stream";
340 throw new java.io.StreamCorruptedException(message);
341 }
342 if (roundingMode == null) {
343 String message = "MathContext: null roundingMode in stream";
344 throw new java.io.StreamCorruptedException(message);
345 }
346 // Set the lookaside, if applicable
347 if (precision <= MAX_LOOKASIDE) {
348 roundingMax = BigInteger.TEN.pow(precision);
349 roundingMin = roundingMax.negate();
350 }
351 }
352
353 }