Reputation: 91969
I am learning scala, and I need to print powers of 2 with its reciprocal from 0 to 20
What I am doing is
scala> for {
| i <- 0 to 20
| pow <- scala.math.pow(2, i).toInt
| rec <- 1/pow
| } println(pow + "\t" + rec)
But I see error as
<console>:13: error: value foreach is not a member of Int
pow <- scala.math.pow(2, i).toInt
^
I know pow
is not iterable, but how can I compute it before so that I reuse it?
Else, I am recomputing it as
scala> for(i <- 0 to 10) println(scala.math.pow(2, i).toInt + "\t" + 1/scala.math.pow(2,i))
1 1.0
2 0.5
4 0.25
8 0.125
16 0.0625
32 0.03125
64 0.015625
128 0.0078125
256 0.00390625
512 0.001953125
1024 9.765625E-4
Ugly, right?
Upvotes: 3
Views: 4243
Reputation: 51271
A rather different approach, using Streams
, offers some flexibility (length of output is chosen by the caller instead of being hard-coded) and memoization (after a value has been calculated it can then be retrieved rather than re-calculated).
// pts --> Powers of Two Stream
val pts: Stream[(Int,Double)] = (1,1.0) #:: fs.zipWithIndex.map{x=>
val p = scala.math.pow(2, x._2+1);
(p.toInt, 1/p)}
scala> pts.take(20).mkString("\n")
res11: String =
(1,1.0)
(2,0.5)
(4,0.25)
(8,0.125)
(16,0.0625)
(32,0.03125)
(64,0.015625)
(128,0.0078125)
(256,0.00390625)
(512,0.001953125)
(1024,9.765625E-4)
(2048,4.8828125E-4)
(4096,2.44140625E-4)
(8192,1.220703125E-4)
(16384,6.103515625E-5)
(32768,3.0517578125E-5)
(65536,1.52587890625E-5)
(131072,7.62939453125E-6)
(262144,3.814697265625E-6)
(524288,1.9073486328125E-6)
Output formatting is left as an exercise for the reader.
Upvotes: 2
Reputation: 15074
When you use <-
in a for comprehension, you need to be providing a type compatible with the output of the first such <-
. Here, you create a Seq[Int]
from the line i <- 0 to 20
, but then an Int
from the next line. Instead, you can just assign the intermediate results, and yield a list at the end (that you can then print out or otherwise work with as you choose).
Also, you should note that by casting to an Int
where you do, you ensure the reciprocal is calculated using integer division, which results in zero for the reciprocal for all but the first power - do the casting to Int
in the yield so you have Double
reciprocals.
Overall:
val result = for {
i <- 0 to 20
pow = scala.math.pow(2, i)
rec = 1/pow
} yield (pow.toInt + "\t" + rec)
You can then print out the results using something like:
println(result.mkString("\n"))
Output will then be something like:
1 1.0
2 0.5
4 0.25
8 0.125
16 0.0625
32 0.03125
64 0.015625
128 0.0078125
256 0.00390625
512 0.001953125
1024 9.765625E-4
2048 4.8828125E-4
4096 2.44140625E-4
8192 1.220703125E-4
16384 6.103515625E-5
32768 3.0517578125E-5
65536 1.52587890625E-5
131072 7.62939453125E-6
262144 3.814697265625E-6
524288 1.9073486328125E-6
1048576 9.5367431640625E-7
Further, you could alter the yield to generate a list of tuples, then format however you choose later (decoupling formatting from generation):
val result = { ... // as before
} yield (i, pow, rec) // Could prove handy to keep the index, and keep pow as a Double for now
def printResults(results: List[(Int, Double, Double)], formatter: (Int, Double, Double) => String) = results forEach { case (n, pow, rec) =>
println(formatter(n, pow, rec))
}
def egFormatter(n: Int, pow: Double, rec: Double) = s"For n = $n,\t 2^n = ${pow.toInt},\t reciprocal = $rec"
printResults(results, egFormatter)
Upvotes: 9