简体   繁体   中英

How to generate Scala Range for Double?

I am not able to generate Scala ranges for Double.

I have read StackOverflow and there are many snippets which show double ranges but none of that works on my Scala REPL 2.13.0

9.474 to 49.474 by 1.0
1d to 1000d by 1d
(1.0 to 2.0 by 0.01)
            ^
       error: value to is not a member of Double

What is the reason I cannot use to and by to generate double ranges in my Scala REPL

I am on a macOS with Scala 2.13.0

With Scala 2.12 I get a deprecation warning:

scala> 9.474 to 49.474 by 1.0
<console>:12: warning: method to in trait FractionalProxy is deprecated (since 2.12.6): use BigDecimal range instead
       9.474 to 49.474 by 1.0

So maybe it is not supported anymore in 2.13. According to the warning you can do:

scala> BigDecimal(9.474) to BigDecimal(49.474) by BigDecimal(1.0)
res6: scala.collection.immutable.NumericRange.Inclusive[scala.math.BigDecimal] = NumericRange 9.474 to 49.474

This also works:

BigDecimal(9.474) to BigDecimal(49.474) by 1

If you do .foreach(println) on both versions you see that without BigDecimal the result looks not so great:

9.474
10.474
..
31.474
32.474000000000004
33.474000000000004
...

From the Release Notes :

Assorted deprecated methods and classes throughout the standard library have been removed entirely.

You can always create your own function that will create Range (or Seq/Iterator) for you.

// https://scastie.scala-lang.org/ZPfpF37bRlKfUPnMyOzJDw

import scala.util.Try

def rangeInclusiveDouble(from:Double, to:Double, by:Double = 1.0) = {
  assume(by != 0, "'by' cannot by 0")
  assume((to - from) * by > 0, "range has reversed order (arguments 'from', 'to' and 'by' will produce infinite range)")
  val check: Double => Boolean = if (by > 0) _ <= to else _ >= to
  Iterator.iterate(from)(_+by).takeWhile(check)
}

//usage example:
rangeInclusiveDouble(1.1, 5.1).toSeq
//List(1.1, 2.1, 3.1, 4.1, 5.1)
rangeInclusiveDouble(1.1, 2.1, 0.1).toSeq //here you will see why range over double is tricky!
//List(1.1, 1.2000000000000002, 1.3000000000000003, 1.4000000000000004,...
Try(rangeInclusiveDouble(5.0, 1.0).toSeq)
// Failure(java.lang.AssertionError: assumption failed: range has reversed order (arguments 'from', 'to' and 'by' will produce infinite range))
Try(rangeInclusiveDouble(5.0, 1.0, 0).toSeq)
//Failure(java.lang.AssertionError: assumption failed: 'by' cannot by 0)
rangeInclusiveDouble(5.0, 1.0, -1).toSeq
//List(5.0, 4.0, 3.0, 2.0, 1.0)

It has its own problems as you can see... but works if you are careful about range limits.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM