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