diff options
-rw-r--r-- | src/library/scala/BigDecimal.scala | 6 | ||||
-rwxr-xr-x | src/library/scala/Numeric.scala | 26 | ||||
-rw-r--r-- | src/library/scala/Range.scala | 42 | ||||
-rw-r--r-- | src/library/scala/runtime/RichDouble.scala | 6 |
4 files changed, 62 insertions, 18 deletions
diff --git a/src/library/scala/BigDecimal.scala b/src/library/scala/BigDecimal.scala index a5faf979e1..9bae9feb01 100644 --- a/src/library/scala/BigDecimal.scala +++ b/src/library/scala/BigDecimal.scala @@ -266,6 +266,12 @@ class BigDecimal(val bigDecimal: BigDec) extends java.lang.Number { */ def doubleValue = this.bigDecimal.doubleValue + /** See <code>Iterator.range</code>. */ + def until(end: BigDecimal, step: BigDecimal) = Range.BigDecimal(this, end, step) + + /** like <code>until</code>, but includes the last index */ + def to(end: BigDecimal, step: BigDecimal) = Range.BigDecimal.inclusive(this, end, step) + /** Converts this <code>BigDecimal</code> to a BigInteger. */ def toBigInt(): BigInt = new BigInt(this.bigDecimal.toBigInteger()) diff --git a/src/library/scala/Numeric.scala b/src/library/scala/Numeric.scala index cd563609c9..a9fc0c08f8 100755 --- a/src/library/scala/Numeric.scala +++ b/src/library/scala/Numeric.scala @@ -73,6 +73,32 @@ object Numeric { def toDouble(x: Double): Double = x } implicit object DoubleIsFractional extends DoubleIsFractional with Ordering.DoubleOrdering + + trait BigDecimalIsConflicted { + def plus(x: BigDecimal, y: BigDecimal): BigDecimal = x + y + def minus(x: BigDecimal, y: BigDecimal): BigDecimal = x - y + def times(x: BigDecimal, y: BigDecimal): BigDecimal = x * y + def negate(x: BigDecimal): BigDecimal = -x + def fromInt(x: Int): BigDecimal = BigDecimal(x) + def toInt(x: BigDecimal): Int = x.intValue + def toLong(x: BigDecimal): Long = x.longValue + def toFloat(x: BigDecimal): Float = x.floatValue + def toDouble(x: BigDecimal): Double = x.doubleValue + } + + trait BigDecimalIsFractional extends BigDecimalIsConflicted with Fractional[BigDecimal] { + def div(x: BigDecimal, y: BigDecimal): BigDecimal = x / y + } + trait BigDecimalAsIfIntegral extends BigDecimalIsConflicted with Integral[BigDecimal] { + def quot(x: BigDecimal, y: BigDecimal): BigDecimal = x / y + // scala.BigDecimal doesn't give access to remainder, grr + def rem(x: BigDecimal, y: BigDecimal): BigDecimal = + new BigDecimal(x.bigDecimal remainder y.bigDecimal) + } + + // The Fractional one is the implicit, but Integral is useful for GenericRange. + implicit object BigDecimalIsFractional extends BigDecimalIsFractional with Ordering.BigDecimalOrdering + object BigDecimalAsIfIntegral extends BigDecimalAsIfIntegral with Ordering.BigDecimalOrdering } trait Numeric[T] extends Ordering[T] { diff --git a/src/library/scala/Range.scala b/src/library/scala/Range.scala index 4cf8bac950..3c8138fb87 100644 --- a/src/library/scala/Range.scala +++ b/src/library/scala/Range.scala @@ -34,21 +34,19 @@ import util.control.Exception.catching * @version 2.8 */ abstract class GenericRange[T] - (val start: T, val end: T, val step: T) + (val start: T, val end: T, val step: T, val isInclusive: Boolean = false) (implicit num: Integral[T]) extends VectorView[T, Vector[T]] with RangeToString[T] { import num._ - // this lets us pretend all ranges are exclusive - val isInclusive: Boolean - private val trueEnd = if (isInclusive) end + one else end - // todo? - we could lift the length restriction by implementing a range as a sequence of // subranges and limiting the subranges to MAX_INT. There's no other way around it because // the generics we inherit assume integer-based indexing (as well they should.) require(!(step equiv zero)) require(genericLength <= fromInt(Math.MAX_INT), "Implementation restricts ranges to Math.MAX_INT elements.") + // By adjusting end based on isInclusive, we can treat all ranges as exclusive. + private lazy val trueEnd: T = if (isInclusive) end + step else end protected def underlying = Vector.empty[T] /** Create a new range with the start and end values of this range and @@ -74,9 +72,8 @@ extends VectorView[T, Vector[T]] with RangeToString[T] { } lazy val genericLength: T = { - def plen(start: T, end: T, step: T) = - if (trueEnd <= start) zero - else (trueEnd - start - one) / step + one + def plen(s: T, e: T, stp: T) = + if (e <= s) zero else ((e - s) / stp) if (step > zero) plen(start, trueEnd, step) else plen(trueEnd, start, -step) @@ -88,7 +85,7 @@ extends VectorView[T, Vector[T]] with RangeToString[T] { def apply(idx: Int): T = applyAt(fromInt(idx)) def applyAt(idx: T): T = { if (idx < zero || idx >= genericLength) throw new IndexOutOfBoundsException(idx.toString) - start + idx * step + start + (idx * step) } // The contains situation makes for some interesting code. @@ -119,7 +116,7 @@ private[scala] trait RangeToString[T] extends VectorView[T, Vector[T]] { // if the Range is unduly large. This interacts poorly with the REPL. override def toString() = { val MAX_PRINT = 512 // some arbitrary value - val str = (this take MAX_PRINT).toString + val str = (this take MAX_PRINT).mkString(", ") if (length > MAX_PRINT) str.replaceAll("""\)$""", ", ...)") else str @@ -128,18 +125,13 @@ private[scala] trait RangeToString[T] extends VectorView[T, Vector[T]] { object GenericRange { - import Numeric._ - class Inclusive[T](start: T, end: T, step: T)(implicit num: Integral[T]) - extends GenericRange(start, end, step) - { - val isInclusive = true + extends GenericRange(start, end, step, true) { def exclusive: Exclusive[T] = new Exclusive(start, end, step) } + class Exclusive[T](start: T, end: T, step: T)(implicit num: Integral[T]) - extends GenericRange(start, end, step) - { - val isInclusive = false + extends GenericRange(start, end, step, false) { def inclusive: Inclusive[T] = new Inclusive(start, end, step) } @@ -229,10 +221,24 @@ object Range { def apply(start: BigInt, end: BigInt, step: BigInt) = GenericRange(start, end, step) def inclusive(start: BigInt, end: BigInt, step: BigInt) = GenericRange.inclusive(start, end, step) } + // The BigDecimal and Double ranges will throw an exception if they cannot + // step exactly as requested. + object BigDecimal { + def apply(start: BigDecimal, end: BigDecimal, step: BigDecimal) = + GenericRange(start, end, step)(Numeric.BigDecimalAsIfIntegral) + def inclusive(start: BigDecimal, end: BigDecimal, step: BigDecimal) = + GenericRange.inclusive(start, end, step)(Numeric.BigDecimalAsIfIntegral) + } object Long { def apply(start: Long, end: Long, step: Long) = GenericRange(start, end, step) def inclusive(start: Long, end: Long, step: Long) = GenericRange.inclusive(start, end, step) } + object Double { + def apply(start: Double, end: Double, step: Double) = + BigDecimal(scala.BigDecimal(start), scala.BigDecimal(end), scala.BigDecimal(step)) + def inclusive(start: Double, end: Double, step: Double) = + BigDecimal.inclusive(scala.BigDecimal(start), scala.BigDecimal(end), scala.BigDecimal(step)) + } // Illustrating genericity with Int Range, which should have the same behavior // as the original Range class. However we leave the original Range diff --git a/src/library/scala/runtime/RichDouble.scala b/src/library/scala/runtime/RichDouble.scala index 8f7d18d167..5c20745f60 100644 --- a/src/library/scala/runtime/RichDouble.scala +++ b/src/library/scala/runtime/RichDouble.scala @@ -29,6 +29,12 @@ final class RichDouble(x: Double) extends Proxy with Ordered[Double] { def ceil: Double = Math.ceil(x) def floor: Double = Math.floor(x) + /** See <code>Iterator.range</code>. */ + def until(end: Double, step: Double) = Range.Double(x, end, step) + + /** like <code>until</code>, but includes the last index */ + def to(end: Double, step: Double) = Range.Double.inclusive(x, end, step) + /** Converts an angle measured in degrees to an approximately equivalent * angle measured in radians. * |