From a46b8b15010eb523cedd8dd23ff7423ca5c73942 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Wed, 10 Jun 2009 21:48:47 +0000 Subject: Trying to bring BigDecimal all the way up to sp... Trying to bring BigDecimal all the way up to speed with its java counterpart. Added a MathContext val and perform all operations with that MathContext, and an apply method which accepts a math context so you can e.g.: val x = BigDecimal(1.0) x / 3 // ArithmeticException x(DECIMAL32) / 3 // 0.3333333 Also added most of the java BigDecimal methods which for whatever reason weren't exposed by the wrapper. Precision to infinity... and beyond! --- src/library/scala/BigDecimal.scala | 115 +++++++++++++++++++++++++------------ 1 file changed, 78 insertions(+), 37 deletions(-) diff --git a/src/library/scala/BigDecimal.scala b/src/library/scala/BigDecimal.scala index a1ae26fc01..54409bfa32 100644 --- a/src/library/scala/BigDecimal.scala +++ b/src/library/scala/BigDecimal.scala @@ -11,24 +11,26 @@ package scala import java.math.{BigDecimal => BigDec} +import java.math.MathContext /** * @author Stephane Micheloud * @version 1.0 */ -object BigDecimal { - +object BigDecimal +{ @serializable - object RoundingMode extends Enumeration { + object RoundingMode extends Enumeration(java.math.RoundingMode.values map (_.toString) : _*) { type RoundingMode = Value - val ROUND_UP, ROUND_DOWN, ROUND_CEILING, ROUND_FLOOR, ROUND_HALF_UP, - ROUND_HALF_DOWN, ROUND_HALF_EVEN, ROUND_UNNECESSARY = Value + val UP, DOWN, CEILING, FLOOR, HALF_UP, HALF_DOWN, HALF_EVEN, UNNECESSARY = Value } private val minCached = -512 private val maxCached = 512 private lazy val cache = new Array[BigDecimal](maxCached - minCached + 1) + val defaultMathContext = MathContext.UNLIMITED + /** Constructs a BigDecimal whose value is equal to that of the * specified Integer value. * @@ -53,6 +55,10 @@ object BigDecimal { if (minCached <= l && l <= maxCached) apply(l.toInt) else new BigDecimal(BigDec.valueOf(l)) + def apply(unscaledVal: Long, scale: Int): BigDecimal = + if (scale == 0) apply(unscaledVal) + else new BigDecimal(BigDec.valueOf(unscaledVal, scale)) + /** Constructs a BigDecimal whose value is equal to that of the * specified double value. * @@ -74,6 +80,9 @@ object BigDecimal { def apply(x: String): BigDecimal = new BigDecimal(new BigDec(x)) + 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. * @@ -113,10 +122,16 @@ object BigDecimal { * @version 1.0 */ @serializable -class BigDecimal(val bigDecimal: BigDec) extends java.lang.Number { +class BigDecimal( + val bigDecimal: BigDec, + val mc: MathContext) +extends java.lang.Number +{ + def this(bigDecimal: BigDec) = this(bigDecimal, BigDecimal.defaultMathContext) import BigDecimal.RoundingMode._ - // import BigDecimal.RoundingMode.{ RoundingMode, ROUND_UP, ROUND_DOWN, ROUND_CEILING, ROUND_FLOOR, - // ROUND_HALF_UP, ROUND_HALF_DOWN, ROUND_HALF_EVEN, ROUND_UNNECESSARY } + + /** 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. */ override def hashCode(): Int = this.bigDecimal.hashCode() @@ -134,76 +149,80 @@ class BigDecimal(val bigDecimal: BigDec) extends java.lang.Number { /** Compares this BigDecimal with the specified BigDecimal for equality. */ - def equals (that: BigDecimal): Boolean = - this.bigDecimal.compareTo(that.bigDecimal) == 0 + 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) + def compare (that: BigDecimal): Int = this.bigDecimal compareTo that.bigDecimal /** Less-than-or-equals comparison of BigDecimals */ - def <= (that: BigDecimal): Boolean = this.bigDecimal.compareTo(that.bigDecimal) <= 0 + def <= (that: BigDecimal): Boolean = compare(that) <= 0 /** Greater-than-or-equals comparison of BigDecimals */ - def >= (that: BigDecimal): Boolean = this.bigDecimal.compareTo(that.bigDecimal) >= 0 + def >= (that: BigDecimal): Boolean = compare(that) >= 0 /** Less-than of BigDecimals */ - def < (that: BigDecimal): Boolean = this.bigDecimal.compareTo(that.bigDecimal) < 0 + def < (that: BigDecimal): Boolean = compare(that) < 0 /** Greater-than comparison of BigDecimals */ - def > (that: BigDecimal): Boolean = this.bigDecimal.compareTo(that.bigDecimal) > 0 + def > (that: BigDecimal): Boolean = compare(that) > 0 /** Addition of BigDecimals */ - def + (that: BigDecimal): BigDecimal = - new BigDecimal(this.bigDecimal.add(that.bigDecimal)) + def + (that: BigDecimal): BigDecimal = this.bigDecimal.add(that.bigDecimal, mc) /** Subtraction of BigDecimals */ - def - (that: BigDecimal): BigDecimal = - new BigDecimal(this.bigDecimal.subtract(that.bigDecimal)) + def - (that: BigDecimal): BigDecimal = this.bigDecimal.subtract(that.bigDecimal, mc) /** Multiplication of BigDecimals */ - def * (that: BigDecimal): BigDecimal = - new BigDecimal(this.bigDecimal.multiply(that.bigDecimal)) + def * (that: BigDecimal): BigDecimal = this.bigDecimal.multiply(that.bigDecimal, mc) /** Division of BigDecimals */ - def / (that: BigDecimal): BigDecimal = - new BigDecimal(this.bigDecimal.divide(that.bigDecimal)) + 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, mc) match { + case Array(q, r) => (q, r) + } + + /** Divide to Integral value. + */ + def quot (that: BigDecimal): BigDecimal = + this.bigDecimal.divideToIntegralValue(that.bigDecimal, mc) /** Returns the minimum of this and that */ - def min (that: BigDecimal): BigDecimal = - new BigDecimal(this.bigDecimal.min(that.bigDecimal)) + def min (that: BigDecimal): BigDecimal = this.bigDecimal min that.bigDecimal /** Returns the maximum of this and that */ - def max (that: BigDecimal): BigDecimal = - new BigDecimal(this.bigDecimal.max(that.bigDecimal)) + def max (that: BigDecimal): BigDecimal = this.bigDecimal max that.bigDecimal /** Remainder after dividing this by that. */ - def remainder (that: BigDecimal): BigDecimal = - new BigDecimal(this.bigDecimal remainder that.bigDecimal) + def remainder (that: BigDecimal): BigDecimal = this.bigDecimal.remainder(that.bigDecimal, mc) /** Returns a BigDecimal whose value is this ** n. */ - def pow (n: Int): BigDecimal = - new BigDecimal(this.bigDecimal pow 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 = new BigDecimal(this.bigDecimal.negate()) + def unary_- : BigDecimal = this.bigDecimal.negate(mc) /** Returns the absolute value of this BigDecimal */ - def abs: BigDecimal = new BigDecimal(this.bigDecimal.abs()) + def abs: BigDecimal = this.bigDecimal abs mc /** Returns the sign of this BigDecimal, i.e. * -1 if it is less than 0, @@ -212,18 +231,33 @@ class BigDecimal(val bigDecimal: BigDec) extends java.lang.Number { */ 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 = - new BigDecimal(this.bigDecimal setScale scale) + def setScale(scale: Int): BigDecimal = this.bigDecimal setScale scale def setScale(scale: Int, mode: RoundingMode): BigDecimal = - new BigDecimal(this.bigDecimal.setScale(scale, mode.id)) + 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. @@ -276,13 +310,20 @@ class BigDecimal(val bigDecimal: BigDec) extends java.lang.Number { */ def doubleValue = this.bigDecimal.doubleValue + /** This BigDecimal as an exact value. + */ + def byteValueExact: Byte = bigDecimal.byteValueExact + def shortValueExact: Short = bigDecimal.shortValueExact + def intValueExact: Int = bigDecimal.intValueExact + def longValueExact: Long = bigDecimal.longValueExact + /** See Iterator.range. */ def until(end: BigDecimal, step: BigDecimal) = Range.BigDecimal(this, end, step) /** like until, but includes the last index */ def to(end: BigDecimal, step: BigDecimal) = Range.BigDecimal.inclusive(this, end, step) - /** Converts this BigDecimal to a BigInteger. + /** Converts this BigDecimal to a scala.BigInt. */ def toBigInt(): BigInt = new BigInt(this.bigDecimal.toBigInteger()) -- cgit v1.2.3