-
Notifications
You must be signed in to change notification settings - Fork 38
Example: Fast exponentiation, streamingly 🌊 #925
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
e38279e
7a92776
316cb82
dbd612a
edc3055
8bb7d80
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
0 | ||
0b0 | ||
0b0 | ||
1 | ||
0b1 | ||
0b1 | ||
2 | ||
0b01 | ||
0b10 | ||
3 | ||
0b11 | ||
0b11 | ||
4 | ||
0b001 | ||
0b100 | ||
123456789 | ||
0b101010001011001111011010111 | ||
0b111010110111100110100010101 | ||
|
||
2 ^ 0 | ||
1 | ||
1 | ||
2 ^ 5 | ||
32 | ||
32 | ||
2 ^ 20 | ||
1048576 | ||
1048576 | ||
10 ^ 10 | ||
10000000000 | ||
10000000000 | ||
0 ^ 1 | ||
0 | ||
0 | ||
1 ^ 0 | ||
1 | ||
1 | ||
0 ^ 0 | ||
1 | ||
1 | ||
200 ^ 2 | ||
40000 | ||
40000 | ||
128 ^ 4 | ||
268435456 | ||
268435456 | ||
7 ^ 13 | ||
96889010407 | ||
96889010407 | ||
13 ^ 7 | ||
62748517 | ||
62748517 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
import stream | ||
|
||
/// Least significant bits | ||
def eachLSB(n: Int): Unit / emit[Bool] = { | ||
if (n <= 0) { | ||
do emit(false) | ||
} else { | ||
var tmp = n | ||
while (tmp > 0) { | ||
do emit(if (tmp.mod(2) == 1) true else false) | ||
tmp = tmp / 2 | ||
} | ||
} | ||
} | ||
|
||
/// Most significant bits | ||
def eachMSB(n: Int): Unit / emit[Bool] = { | ||
if (n <= 0) { | ||
do emit(false) | ||
} else { | ||
// First, calculate the highest bit position | ||
var highest = 0 | ||
var m = n | ||
while (m > 0) { | ||
highest = highest + 1 | ||
m = m / 2 | ||
} | ||
|
||
// Then emit from MSB to LSB | ||
for[Int] { range(0, highest) } { i => | ||
val index = highest - i | ||
val bit = n.bitwiseShr(index - 1).mod(2) == 1 | ||
do emit(bit) | ||
} | ||
} | ||
} | ||
|
||
def fastexp(n: Int, k: Int) = product { | ||
stream::zip[Int, Bool] {n.iterate { x => x * x }} {k.eachLSB} { | ||
case res, true => do emit(res) | ||
case res, false => () | ||
} | ||
} | ||
|
||
def main() = { | ||
/// Computes n^exp for integers. (from #923!) | ||
def pow(n: Int, exp: Int): Int = { | ||
def go(n: Int, exp: Int, acc: Int): Int = { | ||
if (exp == 0) { | ||
acc | ||
} else if (mod(exp, 2) == 0) { | ||
go(n * n, exp / 2, acc) | ||
} else { | ||
go(n * n, exp / 2, acc * n) | ||
} | ||
} | ||
go(n, exp, 1) | ||
} | ||
|
||
def prettyBits(bits: List[Bool]): String = | ||
"0b" ++ bits.map { b => if (b) "1" else "0"}.join("") | ||
|
||
def testBits(n: Int) = { | ||
println(n) | ||
println(collectList[Bool] {n.eachLSB}.prettyBits) | ||
println(collectList[Bool] {n.eachMSB}.prettyBits) | ||
} | ||
|
||
testBits(0) | ||
testBits(1) | ||
testBits(2) | ||
testBits(3) | ||
testBits(4) | ||
testBits(123456789) | ||
|
||
println("") | ||
Comment on lines
+60
to
+76
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This part is just my sanity check for |
||
|
||
def testExp(n: Int, k: Int) = { | ||
println(show(n) ++ " ^ " ++ show(k)) | ||
println(n.pow(k)) | ||
println(n.fastexp(k)) | ||
} | ||
|
||
testExp(2, 0) | ||
testExp(2, 5) | ||
testExp(2, 20) | ||
testExp(10, 10) | ||
testExp(0, 1) | ||
testExp(1, 0) | ||
testExp(0, 0) | ||
testExp(200, 2) | ||
testExp(128, 4) | ||
testExp(7, 13) | ||
testExp(13, 7) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -173,10 +173,23 @@ def replicate[A](number: Int) { action: () => A }: Unit / emit[A] = | |
replicate(number - 1) {action} | ||
} | ||
|
||
/// Creates an infinite iterated stream given by an `initial` seed and a `step` function: | ||
/// iterate(a){f} ~> a, f(a), f(f(a)), f(f(f(a))), ... | ||
def iterate[A](initial: A) { step: A => A }: Unit / emit[A] = { | ||
var current = initial | ||
while (true) { | ||
do emit(current) | ||
current = step(current) | ||
} | ||
} | ||
Comment on lines
+178
to
+184
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice... This looks a lot like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, I just wanted to use the Haskell-style name which (weirdly!) is a bit friendlier than |
||
|
||
|
||
def sum { stream : () => Unit / emit[Int] }: Int = | ||
def sum { stream: () => Unit / emit[Int] }: Int = | ||
returning::sum[Unit]{stream}.second | ||
|
||
def product { stream: () => Unit / emit[Int] }: Int = | ||
returning::product[Unit]{stream}.second | ||
|
||
def collectList[A] { stream: () => Unit / emit[A] }: List[A] = | ||
returning::collectList[A, Unit]{stream}.second | ||
|
||
|
@@ -461,7 +474,7 @@ def limit[A, R](number: Int) { stream: () => R / emit[A] }: R / { emit[A], stop | |
} | ||
} | ||
|
||
def sum[R] { stream : () => R / emit[Int] }: (R, Int) = { | ||
def sum[R] { stream: () => R / emit[Int] }: (R, Int) = { | ||
var s = 0; | ||
try { | ||
(stream(), s) | ||
|
@@ -471,6 +484,16 @@ def sum[R] { stream : () => R / emit[Int] }: (R, Int) = { | |
} | ||
} | ||
|
||
def product[R] { stream: () => R / emit[Int] }: (R, Int) = { | ||
var s = 1; | ||
try { | ||
(stream(), s) | ||
} with emit[Int] { v => | ||
s = s * v; | ||
resume(()) | ||
} | ||
} | ||
|
||
def collectList[A, R] { stream: () => R / emit[A] }: (R, List[A]) = | ||
try { | ||
(stream(), Nil()) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Taken verbatim from #923, I really ought to rebase :)
By the way, as an exercise in algorithms, notice that the
pow
here and thefastexp
above are completely isomorphic, always doing the exact same steps :)