/* __ *\ ** ________ ___ / / ___ Scala API ** ** / __/ __// _ | / / / _ | (c) 2007-2013, LAMP/EPFL ** ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** ** /____/\___/_/ |_/____/_/ | | ** ** |/ ** \* */ package scala package math import scala.language.implicitConversions import java.math.{ MathContext, BigDecimal => BigDec } import scala.collection.immutable.NumericRange /** * @author Stephane Micheloud * @author Rex Kerr * @version 1.1 * @since 2.7 */ object BigDecimal { private final val maximumHashScale = 4934 // Quit maintaining hash identity with BigInt beyond this scale private final val hashCodeNotComputed = 0x5D50690F // Magic value (happens to be "BigDecimal" old MurmurHash3 value) private final val deci2binary = 3.3219280948873626 // Ratio of log(10) to log(2) private val minCached = -512 private val maxCached = 512 val defaultMathContext = MathContext.DECIMAL128 /** Cache only for defaultMathContext using BigDecimals in a small range. */ private lazy val cache = new Array[BigDecimal](maxCached - minCached + 1) object RoundingMode extends Enumeration { // Annoying boilerplate to ensure consistency with java.math.RoundingMode import java.math.{RoundingMode => RM} type RoundingMode = Value val UP = Value(RM.UP.ordinal) val DOWN = Value(RM.DOWN.ordinal) val CEILING = Value(RM.CEILING.ordinal) val FLOOR = Value(RM.FLOOR.ordinal) val HALF_UP = Value(RM.HALF_UP.ordinal) val HALF_DOWN = Value(RM.HALF_DOWN.ordinal) val HALF_EVEN = Value(RM.HALF_EVEN.ordinal) val UNNECESSARY = Value(RM.UNNECESSARY.ordinal) } /** Constructs a `BigDecimal` using the decimal text representation of `Double` value `d`, rounding if necessary. */ def decimal(d: Double, mc: MathContext): BigDecimal = new BigDecimal(new BigDec(java.lang.Double.toString(d), mc), mc) /** Constructs a `BigDecimal` using the decimal text representation of `Double` value `d`. */ def decimal(d: Double): BigDecimal = decimal(d, defaultMathContext) /** Constructs a `BigDecimal` using the decimal text representation of `Float` value `f`, rounding if necessary. * Note that `BigDecimal.decimal(0.1f) != 0.1f` since equality agrees with the `Double` representation, and * `0.1 != 0.1f`. */ def decimal(f: Float, mc: MathContext): BigDecimal = new BigDecimal(new BigDec(java.lang.Float.toString(f), mc), mc) /** Constructs a `BigDecimal` using the decimal text representation of `Float` value `f`. * Note that `BigDecimal.decimal(0.1f) != 0.1f` since equality agrees with the `Double` representation, and * `0.1 != 0.1f`. */ def decimal(f: Float): BigDecimal = decimal(f, defaultMathContext) // This exists solely to avoid conversion from Int/Long to Float, screwing everything up. /** Constructs a `BigDecimal` from a `Long`, rounding if necessary. This is identical to `BigDecimal(l, mc)`. */ def decimal(l: Long, mc: MathContext): BigDecimal = apply(l, mc) // This exists solely to avoid conversion from Int/Long to Float, screwing everything up. /** Constructs a `BigDecimal` from a `Long`. This is identical to `BigDecimal(l)`. */ def decimal(l: Long): BigDecimal = apply(l) /** Constructs a `BigDecimal` using a `java.math.BigDecimal`, rounding if necessary. */ def decimal(bd: BigDec, mc: MathContext): BigDecimal = new BigDecimal(bd.round(mc), mc) /** Constructs a `BigDecimal` by expanding the binary fraction * contained by `Double` value `d` into a decimal representation, * rounding if necessary. When a `Float` is converted to a * `Double`, the binary fraction is preserved, so this method * also works for converted `Float`s. */ def binary(d: Double, mc: MathContext): BigDecimal = new BigDecimal(new BigDec(d, mc), mc) /** Constructs a `BigDecimal` by expanding the binary fraction * contained by `Double` value `d` into a decimal representation. * Note: this also works correctly on converted `Float`s. */ def binary(d: Double): BigDecimal = binary(d, defaultMathContext) /** Constructs a `BigDecimal` from a `java.math.BigDecimal`. The * precision is the default for `BigDecimal` or enough to represent * the `java.math.BigDecimal` exactly, whichever is greater. */ def exact(repr: BigDec): BigDecimal = { val mc = if (repr.precision <= defaultMathContext.getPrecision) defaultMathContext else new MathContext(repr.precision, java.math.RoundingMode.HALF_EVEN) new BigDecimal(repr, mc) } /** Constructs a `BigDecimal` by fully expanding the binary fraction * contained by `Double` value `d`, adjusting the precision as * necessary. Note: this works correctly on converted `Float`s also. */ def exact(d: Double): BigDecimal = exact(new BigDec(d)) /** Constructs a `BigDecimal` that exactly represents a `BigInt`. */ def exact(bi: BigInt): BigDecimal = exact(new BigDec(bi.bigInteger)) /** Constructs a `BigDecimal` that exactly represents a `Long`. Note that * all creation methods for `BigDecimal` that do not take a `MathContext` * represent a `Long`; this is equivalent to `apply`, `valueOf`, etc.. */ def exact(l: Long): BigDecimal = apply(l) /** Constructs a `BigDecimal` that exactly represents the number * specified in a `String`. */ def exact(s: String): BigDecimal = exact(new BigDec(s)) /** Constructs a `BigDecimal` that exactly represents the number * specified in base 10 in a character array. */ def exact(cs: Array[Char]): BigDecimal = exact(new BigDec(cs)) /** Constructs a `BigDecimal` using the java BigDecimal static * valueOf constructor. Equivalent to `BigDecimal.decimal`. * * @param d the specified double value * @return the constructed `BigDecimal` */ def valueOf(d: Double): BigDecimal = apply(BigDec valueOf d) /** Constructs a `BigDecimal` using the java BigDecimal static * valueOf constructor, specifying a `MathContext` that is * used for computations but isn't used for rounding. Use * `BigDecimal.decimal` to use `MathContext` for rounding, * or `BigDecimal(java.math.BigDecimal.valueOf(d), mc)` for * no rounding. * * @param d the specified double value * @param mc the `MathContext` used for future computations * @return the constructed `BigDecimal` */ @deprecated("MathContext is not applied to Doubles in valueOf. Use BigDecimal.decimal to use rounding, or java.math.BigDecimal.valueOf to avoid it.", "2.11.0") def valueOf(d: Double, mc: MathContext): BigDecimal = apply(BigDec valueOf d, mc) /** Constructs a `BigDecimal` using the java BigDecimal static * valueOf constructor. * * @param x the specified `Long` value * @return the constructed `BigDecimal` */ def valueOf(x: Long): BigDecimal = apply(x) /** Constructs a `BigDecimal` using the java BigDecimal static * valueOf constructor. This is unlikely to do what you want; * use `valueOf(f.toDouble)` or `decimal(f)` instead. */ @deprecated("Float arguments to valueOf may not do what you wish. Use decimal or valueOf(f.toDouble).", "2.11.0") def valueOf(f: Float): BigDecimal = valueOf(f.toDouble) /** Constructs a `BigDecimal` using the java BigDecimal static * valueOf constructor. This is unlikely to do what you want; * use `valueOf(f.toDouble)` or `decimal(f)` instead. */ @deprecated("Float arguments to valueOf may not do what you wish. Use decimal or valueOf(f.toDouble).", "2.11.0") def valueOf(f: Float, mc: MathContext): BigDecimal = valueOf(f.toDouble, mc) /** Constructs a `BigDecimal` whose value is equal to that of the * specified `Integer` value. * * @param i the specified integer value * @return the constructed `BigDecimal` */ def apply(i: Int): BigDecimal = apply(i, defaultMathContext) /** Constructs a `BigDecimal` whose value is equal to that of the * specified `Integer` value, rounding if necessary. * * @param i the specified integer value * @param mc the precision and rounding mode for creation of this value and future operations on it * @return the constructed `BigDecimal` */ def apply(i: Int, mc: MathContext): BigDecimal = if (mc == defaultMathContext && minCached <= i && i <= maxCached) { val offset = i - minCached var n = cache(offset) if (n eq null) { n = new BigDecimal(BigDec.valueOf(i.toLong), mc); cache(offset) = n } n } else apply(i.toLong, mc) /** Constructs a `BigDecimal` whose value is equal to that of the * specified long value. * * @param l the specified long value * @return the constructed `BigDecimal` */ def apply(l: Long): BigDecimal = if (minCached <= l && l <= maxCached) apply(l.toInt) else new BigDecimal(BigDec.valueOf(l), defaultMathContext) /** Constructs a `BigDecimal` whose value is equal to that of the * specified long value, but rounded if necessary. * * @param l the specified long value * @param mc the precision and rounding mode for creation of this value and future operations on it * @return the constructed `BigDecimal` */ def apply(l: Long, mc: MathContext): BigDecimal = new BigDecimal(new BigDec(l, mc), mc) /** Constructs a `BigDecimal` whose unscaled value is equal to that * of the specified long value. * * @param unscaledVal the value * @param scale the scale * @return the constructed `BigDecimal` */ def apply(unscaledVal: Long, scale: Int): BigDecimal = apply(BigInt(unscaledVal), scale) /** Constructs a `BigDecimal` whose unscaled value is equal to that * of the specified long value, but rounded if necessary. * * @param unscaledVal the value * @param scale the scale * @param mc the precision and rounding mode for creation of this value and future operations on it * @return the constructed `BigDecimal` */ def apply(unscaledVal: Long, scale: Int, mc: MathContext): BigDecimal = apply(BigInt(unscaledVal), scale, mc) /** Constructs a `BigDecimal` whose value is equal to that of the * specified double value. Equivalent to `BigDecimal.decimal`. * * @param d the specified `Double` value * @return the constructed `BigDecimal` */ def apply(d: Double): BigDecimal = decimal(d, defaultMathContext) // note we don't use the static valueOf because it doesn't let us supply // a MathContext, but we should be duplicating its logic, modulo caching. /** Constructs a `BigDecimal` whose value is equal to that of the * specified double value, but rounded if necessary. Equivalent to * `BigDecimal.decimal`. * * @param d the specified `Double` value * @param mc the precision and rounding mode for creation of this value and future operations on it * @return the constructed `BigDecimal` */ def apply(d: Double, mc: MathContext): BigDecimal = decimal(d, mc) @deprecated("The default conversion from Float may not do what you want. Use BigDecimal.decimal for a String representation, or explicitly convert the Float with .toDouble.", "2.11.0") def apply(x: Float): BigDecimal = apply(x.toDouble) @deprecated("The default conversion from Float may not do what you want. Use BigDecimal.decimal for a String representation, or explicitly convert the Float with .toDouble.", "2.11.0") def apply(x: Float, mc: MathContext): BigDecimal = apply(x.toDouble, mc) /** Translates a character array representation of a `BigDecimal` * into a `BigDecimal`. */ def apply(x: Array[Char]): BigDecimal = exact(x) /** Translates a character array representation of a `BigDecimal` * into a `BigDecimal`, rounding if necessary. */ def apply(x: Array[Char], mc: MathContext): BigDecimal = new BigDecimal(new BigDec(x, mc), mc) /** Translates the decimal String representation of a `BigDecimal` * into a `BigDecimal`. */ def apply(x: String): BigDecimal = exact(x) /** Translates the decimal String representation of a `BigDecimal` * into a `BigDecimal`, rounding if necessary. */ def apply(x: String, mc: MathContext): BigDecimal = new BigDecimal(new BigDec(x, mc), mc) /** Constructs a `BigDecimal` whose value is equal to that of the * specified `BigInt` value. * * @param x the specified `BigInt` value * @return the constructed `BigDecimal` */ def apply(x: BigInt): BigDecimal = exact(x) /** Constructs a `BigDecimal` whose value is equal to that of the * specified `BigInt` value, rounding if necessary. * * @param x the specified `BigInt` value * @param mc the precision and rounding mode for creation of this value and future operations on it * @return the constructed `BigDecimal` */ def apply(x: BigInt, mc: MathContext): BigDecimal = new BigDecimal(new BigDec(x.bigInteger, mc), mc) /** Constructs a `BigDecimal` whose unscaled value is equal to that * of the specified `BigInt` value. * * @param unscaledVal the specified `BigInt` value * @param scale the scale * @return the constructed `BigDecimal` */ def apply(unscaledVal: BigInt, scale: Int): BigDecimal = exact(new BigDec(unscaledVal.bigInteger, scale)) /** Constructs a `BigDecimal` whose unscaled value is equal to that * of the specified `BigInt` value. * * @param unscaledVal the specified `BigInt` value * @param scale the scale * @param mc the precision and rounding mode for creation of this value and future operations on it * @return the constructed `BigDecimal` */ def apply(unscaledVal: BigInt, scale: Int, mc: MathContext): BigDecimal = new BigDecimal(new BigDec(unscaledVal.bigInteger, scale, mc), mc) /** Constructs a `BigDecimal` from a `java.math.BigDecimal`. */ def apply(bd: BigDec): BigDecimal = apply(bd, defaultMathContext) @deprecated("This method appears to round a java.math.BigDecimal but actually doesn't. Use new BigDecimal(bd, mc) instead for no rounding, or BigDecimal.decimal(bd, mc) for rounding.", "2.11.0") def apply(bd: BigDec, mc: MathContext): BigDecimal = new BigDecimal(bd, mc) /** Implicit conversion from `Int` to `BigDecimal`. */ implicit def int2bigDecimal(i: Int): BigDecimal = apply(i) /** Implicit conversion from `Long` to `BigDecimal`. */ implicit def long2bigDecimal(l: Long): BigDecimal = apply(l) /** Implicit conversion from `Double` to `BigDecimal`. */ implicit def double2bigDecimal(d: Double): BigDecimal = decimal(d) /** Implicit conversion from `java.math.BigDecimal` to `scala.BigDecimal`. */ implicit def javaBigDecimal2bigDecimal(x: BigDec): BigDecimal = apply(x) } /** * `BigDecimal` represents decimal floating-point numbers of arbitrary precision. * By default, the precision approximately matches that of IEEE 128-bit floating * point numbers (34 decimal digits, `HALF_EVEN` rounding mode). Within the range * of IEEE binary128 numbers, `BigDecimal` will agree with `BigInt` for both * equality and hash codes (and will agree with primitive types as well). Beyond * that range--numbers with more than 4934 digits when written out in full--the * `hashCode` of `BigInt` and `BigDecimal` is allowed to diverge due to difficulty * in efficiently computing both the decimal representation in `BigDecimal` and the * binary representation in `BigInt`. * * When creating a `BigDecimal` from a `Double` or `Float`, care must be taken as * the binary fraction representation of `Double` and `Float` does not easily * convert into a decimal representation. Three explicit schemes are available * for conversion. `BigDecimal.decimal` will convert the floating-point number * to a decimal text representation, and build a `BigDecimal` based on that. * `BigDecimal.binary` will expand the binary fraction to the requested or default * precision. `BigDecimal.exact` will expand the binary fraction to the * full number of digits, thus producing the exact decimal value corresponding to * the binary fraction of that floating-point number. `BigDecimal` equality * matches the decimal expansion of `Double`: `BigDecimal.decimal(0.1) == 0.1`. * Note that since `0.1f != 0.1`, the same is not true for `Float`. Instead, * `0.1f == BigDecimal.decimal((0.1f).toDouble)`. * * To test whether a `BigDecimal` number can be converted to a `Double` or * `Float` and then back without loss of information by using one of these * methods, test with `isDecimalDouble`, `isBinaryDouble`, or `isExactDouble` * or the corresponding `Float` versions. Note that `BigInt`'s `isValidDouble` * will agree with `isExactDouble`, not the `isDecimalDouble` used by default. * * `BigDecimal` uses the decimal representation of binary floating-point numbers * to determine equality and hash codes. This yields different answers than * conversion between `Long` and `Double` values, where the exact form is used. * As always, since floating-point is a lossy representation, it is advisable to * take care when assuming identity will be maintained across multiple conversions. * * `BigDecimal` maintains a `MathContext` that determines the rounding that * is applied to certain calculations. In most cases, the value of the * `BigDecimal` is also rounded to the precision specified by the `MathContext`. * To create a `BigDecimal` with a different precision than its `MathContext`, * use `new BigDecimal(new java.math.BigDecimal(...), mc)`. Rounding will * be applied on those mathematical operations that can dramatically change the * number of digits in a full representation, namely multiplication, division, * and powers. The left-hand argument's `MathContext` always determines the * degree of rounding, if any, and is the one propagated through arithmetic * operations that do not apply rounding themselves. * * @author Stephane Micheloud * @author Rex Kerr * @version 1.1 */ final class BigDecimal(val bigDecimal: BigDec, val mc: MathContext) extends ScalaNumber with ScalaNumericConversions with Serializable with Ordered[BigDecimal] { def this(bigDecimal: BigDec) = this(bigDecimal, BigDecimal.defaultMathContext) import BigDecimal.RoundingMode._ import BigDecimal.{decimal, binary, exact} if (bigDecimal eq null) throw new IllegalArgumentException("null value for BigDecimal") if (mc eq null) throw new IllegalArgumentException("null MathContext for BigDecimal") // There was an implicit to cut down on the wrapper noise for BigDec -> BigDecimal. // However, this may mask introduction of surprising behavior (e.g. lack of rounding // where one might expect it). Wrappers should be applied explicitly with an // eye to correctness. // Sane hash code computation (which is surprisingly hard). // Note--not lazy val because we can't afford the extra space. private final var computedHashCode: Int = BigDecimal.hashCodeNotComputed private final def computeHashCode(): Unit = { computedHashCode = if (isWhole && (precision - scale) < BigDecimal.maximumHashScale) toBigInt.hashCode else if (isDecimalDouble) doubleValue.## else { val temp = bigDecimal.stripTrailingZeros scala.util.hashing.MurmurHash3.mixLast( temp.scaleByPowerOfTen(temp.scale).toBigInteger.hashCode, temp.scale ) } } /** Returns the hash code for this BigDecimal. * Note that this does not merely use the underlying java object's * `hashCode` because we compare `BigDecimal`s with `compareTo` * which deems 2 == 2.00, whereas in java these are unequal * with unequal `hashCode`s. These hash codes agree with `BigInt` * for whole numbers up ~4934 digits (the range of IEEE 128 bit floating * point). Beyond this, hash codes will disagree; this prevents the * explicit representation of the `BigInt` form for `BigDecimal` values * with large exponents. */ override def hashCode(): Int = { if (computedHashCode == BigDecimal.hashCodeNotComputed) computeHashCode computedHashCode } /** Compares this BigDecimal with the specified value for equality. Where `Float` and `Double` * disagree, `BigDecimal` will agree with the `Double` value */ override def equals (that: Any): Boolean = that match { case that: BigDecimal => this equals that case that: BigInt => that.bitLength > (precision-scale-2)*BigDecimal.deci2binary && this.toBigIntExact.exists(that equals _) case that: Double => !that.isInfinity && { val d = toDouble !d.isInfinity && d == that && equals(decimal(d)) } case that: Float => !that.isInfinity && { val f = toFloat !f.isInfinity && f == that && equals(decimal(f.toDouble)) } case _ => isValidLong && unifiedPrimitiveEquals(that) } override def isValidByte = noArithmeticException(toByteExact) override def isValidShort = noArithmeticException(toShortExact) override def isValidChar = isValidInt && toIntExact >= Char.MinValue && toIntExact <= Char.MaxValue override def isValidInt = noArithmeticException(toIntExact) def isValidLong = noArithmeticException(toLongExact) /** Tests whether the value is a valid Float. "Valid" has several distinct meanings, however. Use * `isExactFloat`, `isBinaryFloat`, or `isDecimalFloat`, depending on the intended meaning. * By default, `decimal` creation is used, so `isDecimalFloat` is probably what you want. */ @deprecated("What constitutes validity is unclear. Use `isExactFloat`, `isBinaryFloat`, or `isDecimalFloat` instead.", "2.11.0") def isValidFloat = { val f = toFloat !f.isInfinity && bigDecimal.compareTo(new BigDec(f.toDouble)) == 0 } /** Tests whether the value is a valid Double. "Valid" has several distinct meanings, however. Use * `isExactDouble`, `isBinaryDouble`, or `isDecimalDouble`, depending on the intended meaning. * By default, `decimal` creation is used, so `isDecimalDouble` is probably what you want. */ @deprecated("Validity has distinct meanings. Use `isExactDouble`, `isBinaryDouble`, or `isDecimalDouble` instead.", "2.11.0") def isValidDouble = { val d = toDouble !d.isInfinity && bigDecimal.compareTo(new BigDec(d)) == 0 } /** Tests whether this `BigDecimal` holds the decimal representation of a `Double`. */ def isDecimalDouble = { val d = toDouble !d.isInfinity && equals(decimal(d)) } /** Tests whether this `BigDecimal` holds the decimal representation of a `Float`. */ def isDecimalFloat = { val f = toFloat !f.isInfinity && equals(decimal(f)) } /** Tests whether this `BigDecimal` holds, to within precision, the binary representation of a `Double`. */ def isBinaryDouble = { val d = toDouble !d.isInfinity && equals(binary(d,mc)) } /** Tests whether this `BigDecimal` holds, to within precision, the binary representation of a `Float`. */ def isBinaryFloat = { val f = toFloat !f.isInfinity && equals(binary(f,mc)) } /** Tests whether this `BigDecimal` holds the exact expansion of a `Double`'s binary fractional form into base 10. */ def isExactDouble = { val d = toDouble !d.isInfinity && equals(exact(d)) } /** Tests whether this `BigDecimal` holds the exact expansion of a `Float`'s binary fractional form into base 10. */ def isExactFloat = { val f = toFloat !f.isInfinity && equals(exact(f.toDouble)) } private def noArithmeticException(body: => Unit): Boolean = { try { body ; true } catch { case _: ArithmeticException => false } } def isWhole() = scale <= 0 || bigDecimal.stripTrailingZeros.scale <= 0 def underlying = bigDecimal /** Compares this BigDecimal with the specified BigDecimal for equality. */ def equals (that: BigDecimal): Boolean = compare(that) == 0 /** Compares this BigDecimal with the specified BigDecimal */ def compare (that: BigDecimal): Int = this.bigDecimal compareTo that.bigDecimal /** Addition of BigDecimals */ def + (that: BigDecimal): BigDecimal = new BigDecimal(this.bigDecimal add that.bigDecimal, mc) /** Subtraction of BigDecimals */ def - (that: BigDecimal): BigDecimal = new BigDecimal(this.bigDecimal subtract that.bigDecimal, mc) /** Multiplication of BigDecimals */ def * (that: BigDecimal): BigDecimal = new BigDecimal(this.bigDecimal.multiply(that.bigDecimal, mc), mc) /** Division of BigDecimals */ def / (that: BigDecimal): BigDecimal = new BigDecimal(this.bigDecimal.divide(that.bigDecimal, mc), mc) /** Division and Remainder - returns tuple containing the result of * divideToIntegralValue and the remainder. The computation is exact: no rounding is applied. */ def /% (that: BigDecimal): (BigDecimal, BigDecimal) = this.bigDecimal.divideAndRemainder(that.bigDecimal) match { case Array(q, r) => (new BigDecimal(q, mc), new BigDecimal(r, mc)) } /** Divide to Integral value. */ def quot (that: BigDecimal): BigDecimal = new BigDecimal(this.bigDecimal divideToIntegralValue that.bigDecimal, mc) /** Returns the minimum of this and that, or this if the two are equal */ def min (that: BigDecimal): BigDecimal = (this compare that) match { case x if x <= 0 => this case _ => that } /** Returns the maximum of this and that, or this if the two are equal */ def max (that: BigDecimal): BigDecimal = (this compare that) match { case x if x >= 0 => this case _ => that } /** Remainder after dividing this by that. */ def remainder (that: BigDecimal): BigDecimal = new BigDecimal(this.bigDecimal remainder that.bigDecimal, mc) /** Remainder after dividing this by that. */ def % (that: BigDecimal): BigDecimal = this remainder that /** Returns a BigDecimal whose value is this ** n. */ def pow (n: Int): BigDecimal = new BigDecimal(this.bigDecimal.pow(n, mc), mc) /** Returns a BigDecimal whose value is the negation of this BigDecimal */ def unary_- : BigDecimal = new BigDecimal(this.bigDecimal.negate(), mc) /** Returns the absolute value of this BigDecimal */ def abs: BigDecimal = if (signum < 0) unary_- else this /** Returns the sign of this BigDecimal; * -1 if it is less than 0, * +1 if it is greater than 0, * 0 if it is equal to 0. */ def signum: Int = this.bigDecimal.signum() /** Returns the precision of this `BigDecimal`. */ def precision: Int = this.bigDecimal.precision() /** Returns a BigDecimal rounded according to the supplied MathContext settings, but * preserving its own MathContext for future operations. */ def round(mc: MathContext): BigDecimal = { val r = this.bigDecimal round mc if (r eq bigDecimal) this else new BigDecimal(r, this.mc) } /** Returns a `BigDecimal` rounded according to its own `MathContext` */ def rounded: BigDecimal = { val r = bigDecimal round mc if (r eq bigDecimal) this else new BigDecimal(r, mc) } /** Returns the scale of this `BigDecimal`. */ def scale: Int = this.bigDecimal.scale() /** Returns the size of an ulp, a unit in the last place, of this BigDecimal. */ def ulp: BigDecimal = new BigDecimal(this.bigDecimal.ulp, mc) /** Returns a new BigDecimal based on the supplied MathContext, rounded as needed. */ def apply(mc: MathContext): BigDecimal = new BigDecimal(this.bigDecimal round mc, mc) /** Returns a `BigDecimal` whose scale is the specified value, and whose value is * numerically equal to this BigDecimal's. */ def setScale(scale: Int): BigDecimal = if (this.scale == scale) this else new BigDecimal(this.bigDecimal setScale scale, mc) def setScale(scale: Int, mode: RoundingMode): BigDecimal = if (this.scale == scale) this else new BigDecimal(this.bigDecimal.setScale(scale, mode.id), mc) /** Converts this BigDecimal to a Byte. * If the BigDecimal is too big to fit in a Byte, only the low-order 8 bits are returned. * Note that this conversion can lose information about the overall magnitude of the * BigDecimal value as well as return a result with the opposite sign. */ override def byteValue = intValue.toByte /** Converts this BigDecimal to a Short. * If the BigDecimal is too big to fit in a Short, only the low-order 16 bits are returned. * Note that this conversion can lose information about the overall magnitude of the * BigDecimal value as well as return a result with the opposite sign. */ override def shortValue = intValue.toShort /** Converts this BigDecimal to a Char. * If the BigDecimal is too big to fit in a Char, only the low-order 16 bits are returned. * Note that this conversion can lose information about the overall magnitude of the * BigDecimal value and that it always returns a positive result. */ def charValue = intValue.toChar /** Converts this BigDecimal to an Int. * If the BigDecimal is too big to fit in an Int, only the low-order 32 bits * are returned. Note that this conversion can lose information about the * overall magnitude of the BigDecimal value as well as return a result with * the opposite sign. */ def intValue = this.bigDecimal.intValue /** Converts this BigDecimal to a Long. * If the BigDecimal is too big to fit in a Long, only the low-order 64 bits * are returned. Note that this conversion can lose information about the * overall magnitude of the BigDecimal value as well as return a result with * the opposite sign. */ def longValue = this.bigDecimal.longValue /** Converts this BigDecimal to a Float. * if this BigDecimal has too great a magnitude to represent as a float, * it will be converted to `Float.NEGATIVE_INFINITY` or * `Float.POSITIVE_INFINITY` as appropriate. */ def floatValue = this.bigDecimal.floatValue /** Converts this BigDecimal to a Double. * if this BigDecimal has too great a magnitude to represent as a double, * it will be converted to `Double.NEGATIVE_INFINITY` or * `Double.POSITIVE_INFINITY` as appropriate. */ def doubleValue = this.bigDecimal.doubleValue /** Converts this `BigDecimal` to a [[scala.Byte]], checking for lost information. * If this `BigDecimal` has a nonzero fractional part, or is out of the possible * range for a [[scala.Byte]] result, then a `java.lang.ArithmeticException` is * thrown. */ def toByteExact = bigDecimal.byteValueExact /** Converts this `BigDecimal` to a [[scala.Short]], checking for lost information. * If this `BigDecimal` has a nonzero fractional part, or is out of the possible * range for a [[scala.Short]] result, then a `java.lang.ArithmeticException` is * thrown. */ def toShortExact = bigDecimal.shortValueExact /** Converts this `BigDecimal` to a [[scala.Int]], checking for lost information. * If this `BigDecimal` has a nonzero fractional part, or is out of the possible * range for an [[scala.Int]] result, then a `java.lang.ArithmeticException` is * thrown. */ def toIntExact = bigDecimal.intValueExact /** Converts this `BigDecimal` to a [[scala.Long]], checking for lost information. * If this `BigDecimal` has a nonzero fractional part, or is out of the possible * range for a [[scala.Long]] result, then a `java.lang.ArithmeticException` is * thrown. */ def toLongExact = bigDecimal.longValueExact /** Creates a partially constructed NumericRange[BigDecimal] in range * `[start;end)`, where start is the target BigDecimal. The step * must be supplied via the "by" method of the returned object in order * to receive the fully constructed range. For example: * {{{ * val partial = BigDecimal(1.0) to 2.0 // not usable yet * val range = partial by 0.01 // now a NumericRange * val range2 = BigDecimal(0) to 1.0 by 0.01 // all at once of course is fine too * }}} * * @param end the end value of the range (exclusive) * @return the partially constructed NumericRange */ def until(end: BigDecimal): Range.Partial[BigDecimal, NumericRange.Exclusive[BigDecimal]] = new Range.Partial(until(end, _)) /** Same as the one-argument `until`, but creates the range immediately. */ def until(end: BigDecimal, step: BigDecimal) = Range.BigDecimal(this, end, step) /** Like `until`, but inclusive of the end value. */ def to(end: BigDecimal): Range.Partial[BigDecimal, NumericRange.Inclusive[BigDecimal]] = new Range.Partial(to(end, _)) /** Like `until`, but inclusive of the end value. */ def to(end: BigDecimal, step: BigDecimal) = Range.BigDecimal.inclusive(this, end, step) /** Converts this `BigDecimal` to a scala.BigInt. */ def toBigInt(): BigInt = new BigInt(this.bigDecimal.toBigInteger()) /** Converts this `BigDecimal` to a scala.BigInt if it * can be done losslessly, returning Some(BigInt) or None. */ def toBigIntExact(): Option[BigInt] = if (isWhole()) { try Some(new BigInt(this.bigDecimal.toBigIntegerExact())) catch { case _: ArithmeticException => None } } else None /** Returns the decimal String representation of this BigDecimal. */ override def toString(): String = this.bigDecimal.toString() }