1 /*
2  * Copyright (c) 2003, 2021, 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     @java.io.Serial
68     private static final long serialVersionUID = 5579720004786848255L;
69 
70     /* ----- Public Properties ----- */
71     /**
72      * A {@code MathContext} object whose settings have the values
73      * required for unlimited precision arithmetic.
74      * The values of the settings are: {@code precision=0 roundingMode=HALF_UP}
75      */
76     public static final MathContext UNLIMITED =
77         new MathContext(0, RoundingMode.HALF_UP);
78 
79     /**
80      * A {@code MathContext} object with a precision setting
81      * matching the precision of the IEEE 754-2019 decimal32 format, 7 digits, and a
82      * rounding mode of {@link RoundingMode#HALF_EVEN HALF_EVEN}.
83      * Note the exponent range of decimal32 is <em>not</em> used for
84      * rounding.
85      */
86     public static final MathContext DECIMAL32 =
87         new MathContext(7, RoundingMode.HALF_EVEN);
88 
89     /**
90      * A {@code MathContext} object with a precision setting
91      * matching the precision of the IEEE 754-2019 decimal64 format, 16 digits, and a
92      * rounding mode of {@link RoundingMode#HALF_EVEN HALF_EVEN}.
93      * Note the exponent range of decimal64 is <em>not</em> used for
94      * rounding.
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 precision of the IEEE 754-2019 decimal128 format, 34 digits, and a
102      * rounding mode of {@link RoundingMode#HALF_EVEN HALF_EVEN}.
103      * Note the exponent range of decimal64 is <em>not</em> used for
104      * rounding.
105      */
106     public static final MathContext DECIMAL128 =
107         new MathContext(34, RoundingMode.HALF_EVEN);
108 
109     /* ----- Shared Properties ----- */
110     /**
111      * The number of digits to be used for an operation.  A value of 0
112      * indicates that unlimited precision (as many digits as are
113      * required) will be used.  Note that leading zeros (in the
114      * coefficient of a number) are never significant.
115      *
116      * <p>{@code precision} will always be non-negative.
117      *
118      * @serial
119      */
120     final int precision;
121 
122     /**
123      * The rounding algorithm to be used for an operation.
124      *
125      * @see RoundingMode
126      * @serial
127      */
128     final RoundingMode roundingMode;
129 
130     /* ----- Constructors ----- */
131 
132     /**
133      * Constructs a new {@code MathContext} with the specified
134      * precision and the {@link RoundingMode#HALF_UP HALF_UP} rounding
135      * mode.
136      *
137      * @param setPrecision The non-negative {@code int} precision setting.
138      * @throws IllegalArgumentException if the {@code setPrecision} parameter is less
139      *         than zero.
140      */
MathContext(int setPrecision)141     public MathContext(int setPrecision) {
142         this(setPrecision, DEFAULT_ROUNDINGMODE);
143         return;
144     }
145 
146     /**
147      * Constructs a new {@code MathContext} with a specified
148      * precision and rounding mode.
149      *
150      * @param setPrecision The non-negative {@code int} precision setting.
151      * @param setRoundingMode The rounding mode to use.
152      * @throws IllegalArgumentException if the {@code setPrecision} parameter is less
153      *         than zero.
154      * @throws NullPointerException if the rounding mode argument is {@code null}
155      */
MathContext(int setPrecision, RoundingMode setRoundingMode)156     public MathContext(int setPrecision,
157                        RoundingMode setRoundingMode) {
158         if (setPrecision < MIN_DIGITS)
159             throw new IllegalArgumentException("Digits < 0");
160         if (setRoundingMode == null)
161             throw new NullPointerException("null RoundingMode");
162 
163         precision = setPrecision;
164         roundingMode = setRoundingMode;
165         return;
166     }
167 
168     /**
169      * Constructs a new {@code MathContext} from a string.
170      *
171      * The string must be in the same format as that produced by the
172      * {@link #toString} method.
173      *
174      * <p>An {@code IllegalArgumentException} is thrown if the precision
175      * section of the string is out of range ({@code < 0}) or the string is
176      * not in the format created by the {@link #toString} method.
177      *
178      * @param val The string to be parsed
179      * @throws IllegalArgumentException if the precision section is out of range
180      * or of incorrect format
181      * @throws NullPointerException if the argument is {@code null}
182      */
MathContext(String val)183     public MathContext(String val) {
184         boolean bad = false;
185         int setPrecision;
186         if (val == null)
187             throw new NullPointerException("null String");
188         try { // any error here is a string format problem
189             if (!val.startsWith("precision=")) throw new RuntimeException();
190             int fence = val.indexOf(' ');    // could be -1
191             int off = 10;                     // where value starts
192             setPrecision = Integer.parseInt(val.substring(10, fence));
193 
194             if (!val.startsWith("roundingMode=", fence+1))
195                 throw new RuntimeException();
196             off = fence + 1 + 13;
197             String str = val.substring(off, val.length());
198             roundingMode = RoundingMode.valueOf(str);
199         } catch (RuntimeException re) {
200             throw new IllegalArgumentException("bad string format");
201         }
202 
203         if (setPrecision < MIN_DIGITS)
204             throw new IllegalArgumentException("Digits < 0");
205         // the other parameters cannot be invalid if we got here
206         precision = setPrecision;
207     }
208 
209     /**
210      * Returns the {@code precision} setting.
211      * This value is always non-negative.
212      *
213      * @return an {@code int} which is the value of the {@code precision}
214      *         setting
215      */
getPrecision()216     public int getPrecision() {
217         return precision;
218     }
219 
220     /**
221      * Returns the roundingMode setting.
222      * This will be one of
223      * {@link  RoundingMode#CEILING},
224      * {@link  RoundingMode#DOWN},
225      * {@link  RoundingMode#FLOOR},
226      * {@link  RoundingMode#HALF_DOWN},
227      * {@link  RoundingMode#HALF_EVEN},
228      * {@link  RoundingMode#HALF_UP},
229      * {@link  RoundingMode#UNNECESSARY}, or
230      * {@link  RoundingMode#UP}.
231      *
232      * @return a {@code RoundingMode} object which is the value of the
233      *         {@code roundingMode} setting
234      */
235 
getRoundingMode()236     public RoundingMode getRoundingMode() {
237         return roundingMode;
238     }
239 
240     /**
241      * Compares this {@code MathContext} with the specified
242      * {@code Object} for equality.
243      *
244      * @param  x {@code Object} to which this {@code MathContext} is to
245      *         be compared.
246      * @return {@code true} if and only if the specified {@code Object} is
247      *         a {@code MathContext} object which has exactly the same
248      *         settings as this object
249      */
equals(Object x)250     public boolean equals(Object x){
251         if (!(x instanceof MathContext mc))
252             return false;
253         return mc.precision == this.precision
254             && mc.roundingMode == this.roundingMode; // no need for .equals()
255     }
256 
257     /**
258      * Returns the hash code for this {@code MathContext}.
259      *
260      * @return hash code for this {@code MathContext}
261      */
hashCode()262     public int hashCode() {
263         return this.precision + roundingMode.hashCode() * 59;
264     }
265 
266     /**
267      * Returns the string representation of this {@code MathContext}.
268      * The {@code String} returned represents the settings of the
269      * {@code MathContext} object as two space-delimited words
270      * (separated by a single space character, <code>'&#92;u0020'</code>,
271      * and with no leading or trailing white space), as follows:
272      * <ol>
273      * <li>
274      * The string {@code "precision="}, immediately followed
275      * by the value of the precision setting as a numeric string as if
276      * generated by the {@link Integer#toString(int) Integer.toString}
277      * method.
278      *
279      * <li>
280      * The string {@code "roundingMode="}, immediately
281      * followed by the value of the {@code roundingMode} setting as a
282      * word.  This word will be the same as the name of the
283      * corresponding public constant in the {@link RoundingMode}
284      * enum.
285      * </ol>
286      * <p>
287      * For example:
288      * <pre>
289      * precision=9 roundingMode=HALF_UP
290      * </pre>
291      *
292      * Additional words may be appended to the result of
293      * {@code toString} in the future if more properties are added to
294      * this class.
295      *
296      * @return a {@code String} representing the context settings
297      */
toString()298     public java.lang.String toString() {
299         return "precision=" +           precision + " " +
300                "roundingMode=" +        roundingMode.toString();
301     }
302 
303     // Private methods
304 
305     /**
306      * Reconstitute the {@code MathContext} instance from a stream (that is,
307      * deserialize it).
308      *
309      * @param  s the stream being read.
310      * @throws IOException if an I/O error occurs
311      * @throws ClassNotFoundException if a serialized class cannot be loaded
312      */
313     @java.io.Serial
readObject(java.io.ObjectInputStream s)314     private void readObject(java.io.ObjectInputStream s)
315         throws java.io.IOException, ClassNotFoundException {
316         s.defaultReadObject();     // read in all fields
317         // validate possibly bad fields
318         if (precision < MIN_DIGITS) {
319             String message = "MathContext: invalid digits in stream";
320             throw new java.io.StreamCorruptedException(message);
321         }
322         if (roundingMode == null) {
323             String message = "MathContext: null roundingMode in stream";
324             throw new java.io.StreamCorruptedException(message);
325         }
326     }
327 
328 }
329