1 /* 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 18 package java.math; 19 20 import java.io.IOException; 21 import java.io.ObjectInputStream; 22 import java.io.Serializable; 23 import 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 */ 29 public 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 */ MathContext(int precision)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 */ MathContext(int precision, RoundingMode roundingMode)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=<precision> roundingMode=<roundingMode>" 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 */ MathContext(String s)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 invalidMathContext(String reason, String s)143 private IllegalArgumentException invalidMathContext(String reason, String s) { 144 throw new IllegalArgumentException(reason + ": " + s); 145 } 146 checkValid()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 */ getPrecision()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 */ getRoundingMode()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 equals(Object x)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 hashCode()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 toString()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 */ readObject(ObjectInputStream s)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 } 250