scala.math.BigDecimal.scala Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of scala-library Show documentation
Show all versions of scala-library Show documentation
Standard library for the Scala Programming Language
/* __ *\
** ________ ___ / / ___ Scala API **
** / __/ __// _ | / / / _ | (c) 2007-2013, LAMP/EPFL **
** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
** /____/\___/_/ |_/____/_/ | | **
** |/ **
\* */
package scala.math
import java.{ lang => jl }
import java.math.{ MathContext, BigDecimal => BigDec }
import scala.collection.immutable.NumericRange
import scala.language.implicitConversions
/**
* @author Stephane Micheloud
* @version 1.0
* @since 2.7
*/
object BigDecimal {
private val minCached = -512
private val maxCached = 512
val defaultMathContext = MathContext.DECIMAL128
@deprecated("Use Long.MinValue", "2.9.0")
val MinLong = new BigDecimal(BigDec valueOf Long.MinValue, defaultMathContext)
@deprecated("Use Long.MaxValue", "2.9.0")
val MaxLong = new BigDecimal(BigDec valueOf Long.MaxValue, defaultMathContext)
/** Cache ony for defaultMathContext using BigDecimals in a small range. */
private lazy val cache = new Array[BigDecimal](maxCached - minCached + 1)
object RoundingMode extends Enumeration {
type RoundingMode = Value
// These are supposed to be the same as java.math.RoundingMode.values,
// though it seems unwise to rely on the correspondence.
val UP, DOWN, CEILING, FLOOR, HALF_UP, HALF_DOWN, HALF_EVEN, UNNECESSARY = Value
}
/** Constructs a `BigDecimal` using the java BigDecimal static
* valueOf constructor.
*
* @param d the specified double value
* @return the constructed `BigDecimal`
*/
def valueOf(d: Double): BigDecimal = apply(BigDec valueOf d)
def valueOf(d: Double, mc: MathContext): BigDecimal = apply(BigDec valueOf d, 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)
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), mc); cache(offset) = n }
n
}
else new BigDecimal(BigDec.valueOf(i), 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)
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)
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.
*
* @param d the specified `Double` value
* @return the constructed `BigDecimal`
*/
def apply(d: Double): BigDecimal = apply(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.
def apply(d: Double, mc: MathContext): BigDecimal =
new BigDecimal(new BigDec(jl.Double.toString(d), mc), mc)
/** Translates a character array representation of a `BigDecimal`
* into a `BigDecimal`.
*/
def apply(x: Array[Char]): BigDecimal = apply(x, defaultMathContext)
def apply(x: Array[Char], mc: MathContext): BigDecimal =
new BigDecimal(new BigDec(x.mkString, mc), mc)
/** Translates the decimal String representation of a `BigDecimal`
* into a `BigDecimal`.
*/
def apply(x: String): BigDecimal = apply(x, defaultMathContext)
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 = apply(x, defaultMathContext)
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 = apply(unscaledVal, scale, defaultMathContext)
def apply(unscaledVal: BigInt, scale: Int, mc: MathContext): BigDecimal =
new BigDecimal(new BigDec(unscaledVal.bigInteger, scale, mc), mc)
def apply(bd: BigDec): BigDecimal = apply(bd, defaultMathContext)
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 = valueOf(d, defaultMathContext)
/** Implicit conversion from `java.math.BigDecimal` to `scala.BigDecimal`. */
implicit def javaBigDecimal2bigDecimal(x: BigDec): BigDecimal = apply(x)
}
/**
* @author Stephane Micheloud
* @version 1.0
*/
@deprecatedInheritance("This class will me made final.", "2.10.0")
class BigDecimal(
val bigDecimal: BigDec,
val mc: MathContext)
extends ScalaNumber with ScalaNumericConversions with Serializable {
def this(bigDecimal: BigDec) = this(bigDecimal, BigDecimal.defaultMathContext)
import BigDecimal.RoundingMode._
/** Cuts way down on the wrapper noise. */
private implicit def bigdec2BigDecimal(x: BigDec): BigDecimal = new BigDecimal(x, mc)
/** Returns the hash code for this BigDecimal.
* Note that this does not use the underlying java object's
* hashCode because we compare BigDecimals with compareTo
* which deems 2 == 2.00, whereas in java these are unequal
* with unequal hashCodes.
*/
override def hashCode(): Int =
if (isWhole) unifiedPrimitiveHashcode
else doubleValue.##
/** Compares this BigDecimal with the specified value for equality.
*/
override def equals (that: Any): Boolean = that match {
case that: BigDecimal => this equals that
case that: BigInt => this.toBigIntExact exists (that equals _)
case that: Double => isValidDouble && toDouble == that
case that: Float => isValidFloat && toFloat == that
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)
/** Returns `true` iff this can be represented exactly by [[scala.Float]]; otherwise returns `false`.
*/
def isValidFloat = {
val f = toFloat
!f.isInfinity && bigDecimal.compareTo(new java.math.BigDecimal(f)) == 0
}
/** Returns `true` iff this can be represented exactly by [[scala.Double]]; otherwise returns `false`.
*/
def isValidDouble = {
val d = toDouble
!d.isInfinity && bigDecimal.compareTo(new java.math.BigDecimal(d)) == 0
}
private def noArithmeticException(body: => Unit): Boolean = {
try { body ; true }
catch { case _: ArithmeticException => false }
}
def isWhole() = (this remainder 1) == BigDecimal(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
/** Less-than-or-equals comparison of BigDecimals
*/
def <= (that: BigDecimal): Boolean = compare(that) <= 0
/** Greater-than-or-equals comparison of BigDecimals
*/
def >= (that: BigDecimal): Boolean = compare(that) >= 0
/** Less-than of BigDecimals
*/
def < (that: BigDecimal): Boolean = compare(that) < 0
/** Greater-than comparison of BigDecimals
*/
def > (that: BigDecimal): Boolean = compare(that) > 0
/** Addition of BigDecimals
*/
def + (that: BigDecimal): BigDecimal = this.bigDecimal.add(that.bigDecimal)
/** Subtraction of BigDecimals
*/
def - (that: BigDecimal): BigDecimal = this.bigDecimal.subtract(that.bigDecimal)
/** Multiplication of BigDecimals
*/
def * (that: BigDecimal): BigDecimal = this.bigDecimal.multiply(that.bigDecimal, mc)
/** Division of BigDecimals
*/
def / (that: BigDecimal): BigDecimal = this.bigDecimal.divide(that.bigDecimal, mc)
/** Division and Remainder - returns tuple containing the result of
* divideToIntegralValue and the remainder.
*/
def /% (that: BigDecimal): (BigDecimal, BigDecimal) =
this.bigDecimal.divideAndRemainder(that.bigDecimal) match {
case Array(q, r) => (q, r)
}
/** Divide to Integral value.
*/
def quot (that: BigDecimal): BigDecimal =
this.bigDecimal.divideToIntegralValue(that.bigDecimal)
/** Returns the minimum of this and that
*/
def min (that: BigDecimal): BigDecimal = this.bigDecimal min that.bigDecimal
/** Returns the maximum of this and that
*/
def max (that: BigDecimal): BigDecimal = this.bigDecimal max that.bigDecimal
/** Remainder after dividing this by that.
*/
def remainder (that: BigDecimal): BigDecimal = this.bigDecimal.remainder(that.bigDecimal)
/** 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 = this.bigDecimal.pow(n, mc)
/** Returns a BigDecimal whose value is the negation of this BigDecimal
*/
def unary_- : BigDecimal = this.bigDecimal.negate()
/** Returns the absolute value of this BigDecimal
*/
def abs: BigDecimal = this.bigDecimal.abs
/** Returns the sign of this BigDecimal, i.e.
* -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 MathContext settings.
*/
def round(mc: MathContext): BigDecimal = this.bigDecimal round 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 = this.bigDecimal.ulp
/** Returns a new BigDecimal based on the supplied MathContext.
*/
def apply(mc: MathContext): BigDecimal = BigDecimal(this.bigDecimal.toString, 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 = this.bigDecimal setScale scale
def setScale(scale: Int, mode: RoundingMode): BigDecimal =
this.bigDecimal.setScale(scale, mode.id)
/** 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 Byte, 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 a char, 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 char, 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] =
try Some(new BigInt(this.bigDecimal.toBigIntegerExact()))
catch { case _: ArithmeticException => None }
/** Returns the decimal String representation of this BigDecimal.
*/
override def toString(): String = this.bigDecimal.toString()
}