/* * @(#)MathContext.java 1.2 03/12/19 * * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ /* * @(#)MathContext.java 1.x 01/xx/xx * * Copyright IBM Corporation, 1997, 2001. All Rights Reserved. * * This software is the proprietary information of Sun Microsystems, Inc. * and IBM Corporation. Use is subject to license terms. * */ package java.math; import java.io.*; /** * Immutable objects which encapsulate the context settings which * describe certain rules for numerical operators, such as those * implemented by the {@link BigDecimal} class. * *

The base-independent settings are: *

    *
  1. precision: * the number of digits to be used for an operation; results are * rounded to this precision * *
  2. roundingMode: * a {@link RoundingMode} object which specifies the algorithm to be * used for rounding. *
* * @see BigDecimal * @see RoundingMode * @author Mike Cowlishaw * @author Joseph D. Darcy */ public final class MathContext implements Serializable { /* ----- Constants ----- */ // defaults for constructors private static final int DEFAULT_DIGITS = 9; private static final RoundingMode DEFAULT_ROUNDINGMODE = RoundingMode.HALF_UP; // Smallest values for digits (Maximum is Integer.MAX_VALUE) private static final int MIN_DIGITS = 0; // Serialization version private static final long serialVersionUID = 5579720004786848255L; /* ----- Public Properties ----- */ /** * A MathContext object whose settings have the values * required for unlimited precision arithmetic. * The values of the settings are: * * precision=0 roundingMode=HALF_UP * */ public static final MathContext UNLIMITED = new MathContext(0, RoundingMode.HALF_UP); /** * A MathContext object with a precision setting * matching the IEEE 754R Decimal32 format, 7 digits, and a * rounding mode of {@link RoundingMode#HALF_EVEN HALF_EVEN}, the * IEEE 754R default. */ public static final MathContext DECIMAL32 = new MathContext(7, RoundingMode.HALF_EVEN); /** * A MathContext object with a precision setting * matching the IEEE 754R Decimal64 format, 16 digits, and a * rounding mode of {@link RoundingMode#HALF_EVEN HALF_EVEN}, the * IEEE 754R default. */ public static final MathContext DECIMAL64 = new MathContext(16, RoundingMode.HALF_EVEN); /** * A MathContext object with a precision setting * matching the IEEE 754R Decimal128 format, 34 digits, and a * rounding mode of {@link RoundingMode#HALF_EVEN HALF_EVEN}, the * IEEE 754R default. */ public static final MathContext DECIMAL128 = new MathContext(34, RoundingMode.HALF_EVEN); /* ----- Shared Properties ----- */ /** * The number of digits to be used for an operation. A value of 0 * indicates that unlimited precision (as many digits as are * required) will be used. Note that leading zeros (in the * coefficient of a number) are never significant. * *

precision will always be non-negative. * * @serial */ final int precision; /** * The rounding algorithm to be used for an operation. * * @see RoundingMode * @serial */ final RoundingMode roundingMode; /** * Lookaside for the rounding points (the numbers which determine * whether the coefficient of a number will require rounding). * These will be present if precision>0 and * precision<=MAX_LOOKASIDE. In this case they will share the * BigInteger int[] array. Note that the transients * cannot be final because they are reconstructed on * deserialization. */ transient BigInteger roundingMax = null; transient BigInteger roundingMin = null; private static final int MAX_LOOKASIDE = 1000; /* ----- Constructors ----- */ /** * Constructs a new MathContext with the specified * precision and the {@link RoundingMode#HALF_UP HALF_UP} rounding * mode. * * @param setPrecision The non-negative int precision setting. * @throws IllegalArgumentException setPrecision parameter less * than zero. */ public MathContext(int setPrecision) { this(setPrecision, DEFAULT_ROUNDINGMODE); return; } /** * Constructs a new MathContext with a specified * precision and rounding mode. * * @param setPrecision The non-negative int precision setting. * @param setRoundingMode The rounding mode to use. * @throws IllegalArgumentException setPrecision parameter less * than zero. */ public MathContext(int setPrecision, RoundingMode setRoundingMode) { if (setPrecision < MIN_DIGITS) throw new IllegalArgumentException("Digits < 0"); if (setRoundingMode == null) throw new NullPointerException("null RoundingMode"); precision = setPrecision; if (precision > 0 && precision <= MAX_LOOKASIDE) { roundingMax = BigInteger.TEN.pow(precision); roundingMin = roundingMax.negate(); } roundingMode = setRoundingMode; return; } /** * Constructs a new MathContext from a string. * * The string must be in the same format as that produced by the * {@link #toString} method. * *

An IllegalArgumentException is thrown if the precision * section of the string is out of range (< 0) or the string is * not in the format created by the {@link #toString} method. * * @param val The string to be parsed * @throws IllegalArgumentException precision parameter out of range * or incorrect format */ public MathContext(String val) { boolean bad = false; int setPrecision; if (val == null) throw new NullPointerException("null String"); try { // any error here is a string format problem if (!val.startsWith("precision=")) throw new RuntimeException(); int fence = val.indexOf(' '); // could be -1 int off = 10; // where value starts setPrecision = Integer.parseInt(val.substring(10, fence)); if (!val.startsWith("roundingMode=", fence+1)) throw new RuntimeException(); off = fence + 1 + 13; String str = val.substring(off, val.length()); roundingMode = RoundingMode.valueOf(str); } catch (RuntimeException re) { throw new IllegalArgumentException("bad string format"); } if (setPrecision < MIN_DIGITS) throw new IllegalArgumentException("Digits < 0"); // the other parameters cannot be invalid if we got here precision = setPrecision; if (precision > 0 && precision <= MAX_LOOKASIDE) { roundingMax = BigInteger.TEN.pow(precision); roundingMin = roundingMax.negate(); } } /** * Returns the precision setting. * This value is always non-negative. * * @return an int which is the value of the precision * setting */ public int getPrecision() { return precision; } /** * Returns the roundingMode setting. * This will be one of * {@link RoundingMode#CEILING}, * {@link RoundingMode#DOWN}, * {@link RoundingMode#FLOOR}, * {@link RoundingMode#HALF_DOWN}, * {@link RoundingMode#HALF_EVEN}, * {@link RoundingMode#HALF_UP}, * {@link RoundingMode#UNNECESSARY}, or * {@link RoundingMode#UP}. * * @return a RoundingMode object which is the value of the * roundingMode setting */ public RoundingMode getRoundingMode() { return roundingMode; } /** * Compares this MathContext with the specified * Object for equality. * * @param x Object to which this MathContext is to * be compared. * @return true if and only if the specified Object is * a MathContext object which has exactly the same * settings as this object. */ public boolean equals(Object x){ MathContext mc; if (!(x instanceof MathContext)) return false; mc = (MathContext) x; return mc.precision == this.precision && mc.roundingMode == this.roundingMode; // no need for .equals() } /** * Returns the hash code for this MathContext. * * @return hash code for this MathContext */ public int hashCode() { return this.precision + roundingMode.hashCode() * 59; } /** * Returns the string representation of this MathContext. * The String returned represents the settings of the * MathContext object as two space-delimited words * (separated by a single space character, '\u0020', * and with no leading or trailing white space), as follows: *

    *
  1. * The string "precision=", immediately followed * by the value of the precision setting as a numeric string as if * generated by the {@link Integer#toString(int) Integer.toString} * method. * *
  2. * The string "roundingMode=", immediately * followed by the value of the roundingMode setting as a * word. This word will be the same as the name of the * corresponding public constant in the {@link RoundingMode} * enum. *
*

* For example: *

     * precision=9 roundingMode=HALF_UP
     * 
* * Additional words may be appended to the result of * toString in the future if more properties are added to * this class. * * @return a String representing the context settings. */ public java.lang.String toString() { return "precision=" + precision + " " + "roundingMode=" + roundingMode.toString(); } // Private methods /** * Reconstitute the MathContext instance from a stream (that is, * deserialize it). * * @param s the stream being read. */ private synchronized void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { s.defaultReadObject(); // read in all fields // validate possibly bad fields if (precision < MIN_DIGITS) { String message = "MathContext: invalid digits in stream"; throw new java.io.StreamCorruptedException(message); } if (roundingMode == null) { String message = "MathContext: null roundingMode in stream"; throw new java.io.StreamCorruptedException(message); } // Set the lookaside, if applicable if (precision <= MAX_LOOKASIDE) { roundingMax = BigInteger.TEN.pow(precision); roundingMin = roundingMax.negate(); } } }