blob: 6f3f1edf6a2fa62c4cb448ac8e0f27cc0a1629a0 [file] [log] [blame]
Alan Viverette3da604b2020-06-10 18:34:39 +00001/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18package java.math;
19
20import java.io.IOException;
21import java.io.ObjectInputStream;
22import java.io.Serializable;
23import java.io.StreamCorruptedException;
24
25/**
26 * Immutable objects describing settings such as rounding mode and digit
27 * precision for the numerical operations provided by class {@link BigDecimal}.
28 */
29public final class MathContext implements Serializable {
30 private static final long serialVersionUID = 5579720004786848255L;
31
32 /**
33 * A {@code MathContext} which corresponds to the <a href="http://en.wikipedia.org/wiki/IEEE_754-1985">IEEE 754</a> quadruple
34 * decimal precision format: 34 digit precision and
35 * {@link RoundingMode#HALF_EVEN} rounding.
36 */
37 public static final MathContext DECIMAL128 = new MathContext(34, RoundingMode.HALF_EVEN);
38
39 /**
40 * A {@code MathContext} which corresponds to the <a href="http://en.wikipedia.org/wiki/IEEE_754-1985">IEEE 754</a> single decimal
41 * precision format: 7 digit precision and {@link RoundingMode#HALF_EVEN}
42 * rounding.
43 */
44 public static final MathContext DECIMAL32 = new MathContext(7, RoundingMode.HALF_EVEN);
45
46 /**
47 * A {@code MathContext} which corresponds to the <a href="http://en.wikipedia.org/wiki/IEEE_754-1985">IEEE 754</a> double decimal
48 * precision format: 16 digit precision and {@link RoundingMode#HALF_EVEN}
49 * rounding.
50 */
51 public static final MathContext DECIMAL64 = new MathContext(16, RoundingMode.HALF_EVEN);
52
53 /**
54 * A {@code MathContext} for unlimited precision with
55 * {@link RoundingMode#HALF_UP} rounding.
56 */
57 public static final MathContext UNLIMITED = new MathContext(0, RoundingMode.HALF_UP);
58
59 /**
60 * The number of digits to be used for an operation; results are rounded to
61 * this precision.
62 */
63 private final int precision;
64
65 /**
66 * A {@code RoundingMode} object which specifies the algorithm to be used
67 * for rounding.
68 */
69 private final RoundingMode roundingMode;
70
71 /**
72 * Constructs a new {@code MathContext} with the specified precision and
73 * with the rounding mode {@link RoundingMode#HALF_UP HALF_UP}. If the
74 * precision passed is zero, then this implies that the computations have to
75 * be performed exact, the rounding mode in this case is irrelevant.
76 *
77 * @param precision
78 * the precision for the new {@code MathContext}.
79 * @throws IllegalArgumentException
80 * if {@code precision < 0}.
81 */
82 public MathContext(int precision) {
83 this(precision, RoundingMode.HALF_UP);
84 }
85
86 /**
87 * Constructs a new {@code MathContext} with the specified precision and
88 * with the specified rounding mode. If the precision passed is zero, then
89 * this implies that the computations have to be performed exact, the
90 * rounding mode in this case is irrelevant.
91 *
92 * @param precision
93 * the precision for the new {@code MathContext}.
94 * @param roundingMode
95 * the rounding mode for the new {@code MathContext}.
96 * @throws IllegalArgumentException
97 * if {@code precision < 0}.
98 * @throws NullPointerException
99 * if {@code roundingMode} is {@code null}.
100 */
101 public MathContext(int precision, RoundingMode roundingMode) {
102 this.precision = precision;
103 this.roundingMode = roundingMode;
104 checkValid();
105 }
106
107 /**
108 * Constructs a new {@code MathContext} from a string. The string has to
109 * specify the precision and the rounding mode to be used and has to follow
110 * the following syntax: "precision=&lt;precision&gt; roundingMode=&lt;roundingMode&gt;"
111 * This is the same form as the one returned by the {@link #toString}
112 * method.
113 *
114 * @throws IllegalArgumentException
115 * if the string is not in the correct format or if the
116 * precision specified is < 0.
117 */
118 public MathContext(String s) {
119 int precisionLength = "precision=".length();
120 int roundingModeLength = "roundingMode=".length();
121
122 int spaceIndex;
123 if (!s.startsWith("precision=") || (spaceIndex = s.indexOf(' ', precisionLength)) == -1) {
124 throw invalidMathContext("Missing precision", s);
125 }
126 String precisionString = s.substring(precisionLength, spaceIndex);
127 try {
128 this.precision = Integer.parseInt(precisionString);
129 } catch (NumberFormatException nfe) {
130 throw invalidMathContext("Bad precision", s);
131 }
132
133 int roundingModeStart = spaceIndex + 1;
134 if (!s.regionMatches(roundingModeStart, "roundingMode=", 0, roundingModeLength)) {
135 throw invalidMathContext("Missing rounding mode", s);
136 }
137 roundingModeStart += roundingModeLength;
138 this.roundingMode = RoundingMode.valueOf(s.substring(roundingModeStart));
139
140 checkValid();
141 }
142
143 private IllegalArgumentException invalidMathContext(String reason, String s) {
144 throw new IllegalArgumentException(reason + ": " + s);
145 }
146
147 private void checkValid() {
148 if (precision < 0) {
149 throw new IllegalArgumentException("Negative precision: " + precision);
150 }
151 if (roundingMode == null) {
152 throw new NullPointerException("roundingMode == null");
153 }
154 }
155
156 /**
157 * Returns the precision. The precision is the number of digits used for an
158 * operation. Results are rounded to this precision. The precision is
159 * guaranteed to be non negative. If the precision is zero, then the
160 * computations have to be performed exact, results are not rounded in this
161 * case.
162 *
163 * @return the precision.
164 */
165 public int getPrecision() {
166 return precision;
167 }
168
169 /**
170 * Returns the rounding mode. The rounding mode is the strategy to be used
171 * to round results.
172 * <p>
173 * The rounding mode is one of
174 * {@link RoundingMode#UP},
175 * {@link RoundingMode#DOWN},
176 * {@link RoundingMode#CEILING},
177 * {@link RoundingMode#FLOOR},
178 * {@link RoundingMode#HALF_UP},
179 * {@link RoundingMode#HALF_DOWN},
180 * {@link RoundingMode#HALF_EVEN}, or
181 * {@link RoundingMode#UNNECESSARY}.
182 *
183 * @return the rounding mode.
184 */
185 public RoundingMode getRoundingMode() {
186 return roundingMode;
187 }
188
189 /**
190 * Returns true if x is a {@code MathContext} with the same precision
191 * setting and the same rounding mode as this {@code MathContext} instance.
192 *
193 * @param x
194 * object to be compared.
195 * @return {@code true} if this {@code MathContext} instance is equal to the
196 * {@code x} argument; {@code false} otherwise.
197 */
198 @Override
199 public boolean equals(Object x) {
200 return ((x instanceof MathContext)
201 && (((MathContext) x).getPrecision() == precision) && (((MathContext) x)
202 .getRoundingMode() == roundingMode));
203 }
204
205 /**
206 * Returns the hash code for this {@code MathContext} instance.
207 *
208 * @return the hash code for this {@code MathContext}.
209 */
210 @Override
211 public int hashCode() {
212 // Make place for the necessary bits to represent 8 rounding modes
213 return ((precision << 3) | roundingMode.ordinal());
214 }
215
216 /**
217 * Returns the string representation for this {@code MathContext} instance.
218 * The string has the form
219 * {@code
220 * "precision=<precision> roundingMode=<roundingMode>"
221 * } where {@code <precision>} is an integer describing the number
222 * of digits used for operations and {@code <roundingMode>} is the
223 * string representation of the rounding mode.
224 *
225 * @return a string representation for this {@code MathContext} instance
226 */
227 @Override
228 public String toString() {
229 return "precision=" + precision + " roundingMode=" + roundingMode;
230 }
231
232 /**
233 * Makes checks upon deserialization of a {@code MathContext} instance.
234 * Checks whether {@code precision >= 0} and {@code roundingMode != null}
235 *
236 * @throws StreamCorruptedException
237 * if {@code precision < 0}
238 * @throws StreamCorruptedException
239 * if {@code roundingMode == null}
240 */
241 private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
242 s.defaultReadObject();
243 try {
244 checkValid();
245 } catch (Exception ex) {
246 throw new StreamCorruptedException(ex.getMessage());
247 }
248 }
249}