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>'\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