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     @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:
  75      *  <code>
  76      *  precision=0 roundingMode=HALF_UP
  77      *  </code>
  78      */
  79     public static final MathContext UNLIMITED =
  80         new MathContext(0, RoundingMode.HALF_UP);
  81 
  82     /**
  83      *  A {@code MathContext} object with a precision setting
  84      *  matching the IEEE 754R Decimal32 format, 7 digits, and a
  85      *  rounding mode of {@link RoundingMode#HALF_EVEN HALF_EVEN}, the
  86      *  IEEE 754R default.
  87      */
  88     public static final MathContext DECIMAL32 =
  89         new MathContext(7, RoundingMode.HALF_EVEN);
  90 
  91     /**
  92      *  A {@code MathContext} object with a precision setting
  93      *  matching the IEEE 754R Decimal64 format, 16 digits, and a
  94      *  rounding mode of {@link RoundingMode#HALF_EVEN HALF_EVEN}, the
  95      *  IEEE 754R default.
  96      */
  97     public static final MathContext DECIMAL64 =
  98         new MathContext(16, RoundingMode.HALF_EVEN);
  99 
 100     /**
 101      *  A {@code MathContext} object with a precision setting
 102      *  matching the IEEE 754R Decimal128 format, 34 digits, and a
 103      *  rounding mode of {@link RoundingMode#HALF_EVEN HALF_EVEN}, the
 104      *  IEEE 754R default.
 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      */
 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      */
 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      */
 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      */
 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 
 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      */
 250     public boolean equals(Object x){
 251         MathContext mc;
 252         if (!(x instanceof MathContext))
 253             return false;
 254         mc = (MathContext) x;
 255         return mc.precision == this.precision
 256             && mc.roundingMode == this.roundingMode; // no need for .equals()
 257     }
 258 
 259     /**
 260      * Returns the hash code for this {@code MathContext}.
 261      *
 262      * @return hash code for this {@code MathContext}
 263      */
 264     public int hashCode() {
 265         return this.precision + roundingMode.hashCode() * 59;
 266     }
 267 
 268     /**
 269      * Returns the string representation of this {@code MathContext}.
 270      * The {@code String} returned represents the settings of the
 271      * {@code MathContext} object as two space-delimited words
 272      * (separated by a single space character, <code>'\u0020'</code>,
 273      * and with no leading or trailing white space), as follows:
 274      * <ol>
 275      * <li>
 276      * The string {@code "precision="}, immediately followed
 277      * by the value of the precision setting as a numeric string as if
 278      * generated by the {@link Integer#toString(int) Integer.toString}
 279      * method.
 280      *
 281      * <li>
 282      * The string {@code "roundingMode="}, immediately
 283      * followed by the value of the {@code roundingMode} setting as a
 284      * word.  This word will be the same as the name of the
 285      * corresponding public constant in the {@link RoundingMode}
 286      * enum.
 287      * </ol>
 288      * <p>
 289      * For example:
 290      * <pre>
 291      * precision=9 roundingMode=HALF_UP
 292      * </pre>
 293      *
 294      * Additional words may be appended to the result of
 295      * {@code toString} in the future if more properties are added to
 296      * this class.
 297      *
 298      * @return a {@code String} representing the context settings
 299      */
 300     public java.lang.String toString() {
 301         return "precision=" +           precision + " " +
 302                "roundingMode=" +        roundingMode.toString();
 303     }
 304 
 305     // Private methods
 306 
 307     /**
 308      * Reconstitute the {@code MathContext} instance from a stream (that is,
 309      * deserialize it).
 310      *
 311      * @param s the stream being read.
 312      */
 313     @java.io.Serial
 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 }