summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2009-06-05 21:08:02 +0000
committerPaul Phillips <paulp@improving.org>2009-06-05 21:08:02 +0000
commitc260301efef7c83d6fb8094954ae0ae555dc5b0f (patch)
tree1884e94efefa23ad91c5e597cf69f33cde79b6ec /src
parent9f6fe27b218039362ce72d90e548e06eed323dc7 (diff)
downloadscala-c260301efef7c83d6fb8094954ae0ae555dc5b0f.tar.gz
scala-c260301efef7c83d6fb8094954ae0ae555dc5b0f.tar.bz2
scala-c260301efef7c83d6fb8094954ae0ae555dc5b0f.zip
Fixed a couple bugs in GenericRange and added t...
Fixed a couple bugs in GenericRange and added the fun and exciting BigDecimal Range. It throws an exception if it ever can't do anything exactly, so it shouldn't be too dangerous to rely upon.
Diffstat (limited to 'src')
-rw-r--r--src/library/scala/BigDecimal.scala6
-rwxr-xr-xsrc/library/scala/Numeric.scala26
-rw-r--r--src/library/scala/Range.scala42
-rw-r--r--src/library/scala/runtime/RichDouble.scala6
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.
*