Skip to content

Commit 1a71751

Browse files
jiribenesLena Käufel
authored andcommitted
Add binary search benchmark (effekt-lang#904)
Add binary search inspired by Jules Jacobs and Brent Yorgey. The interesting part is the missed optimisations --- if you comment out `150.findSqrtUpTo(100)`, you get _much_ better IR and JS code :) This could be made into a parametric benchmark: given N, search between 0 and N\*N for sqrt(N\*N).
1 parent 86ebd77 commit 1a71751

File tree

2 files changed

+55
-0
lines changed

2 files changed

+55
-0
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
sqrt of 150 is between:
2+
12 (^2 = 144)
3+
13 (^2 = 169)
4+
sqrt of 9876543210123 is between:
5+
3142696 (^2 = 9876538148416)
6+
3142697 (^2 = 9876544433809)
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
module binarysearch
2+
3+
// Effectful binary search
4+
// ... inspired by Jules Jacobs https://julesjacobs.com/notes/binarysearch/binarysearch.pdf
5+
// ... ... and Brent Yorgey https://byorgey.wordpress.com/2023/01/01/competitive-programming-in-haskell-better-binary-search/
6+
7+
effect breakWith[A](value: A): Nothing
8+
effect mid[A](l: A, r: A): A / breakWith[(A, A)]
9+
10+
def break2[A, B](x: A, y: B) =
11+
do breakWith((x, y))
12+
def boundary[A] { prog: => A / breakWith[A] }: A =
13+
try prog() with breakWith[A] { a => a }
14+
15+
def search[A](l: A, r: A) { predicate: A => Bool }: (A, A) / mid[A] = boundary[(A, A)] {
16+
def go(l: A, r: A): (A, A) = {
17+
val m = do mid(l, r)
18+
if (predicate(m)) {
19+
go(l, m)
20+
} else {
21+
go(m, r)
22+
}
23+
}
24+
go(l, r)
25+
}
26+
27+
def binary[R] { prog: => R / mid[Int] }: R =
28+
try prog() with mid[Int] { (l, r) =>
29+
resume {
30+
if ((r - l) > 1) {
31+
(l + r) / 2
32+
} else {
33+
break2(l, r)
34+
}
35+
}
36+
}
37+
38+
def main() = binary {
39+
def findSqrtUpTo(pow2: Int, max: Int) = {
40+
val (l, r) = search(0, max) { x => x * x >= pow2 }
41+
println("sqrt of " ++ pow2.show ++ " is between:")
42+
println(l.show ++ " (^2 = " ++ (l * l).show ++ ")")
43+
println(r.show ++ " (^2 = " ++ (r * r).show ++ ")")
44+
}
45+
46+
// Comment out the first call below to get much better JS/Core codegen:
47+
findSqrtUpTo(150, 100)
48+
findSqrtUpTo(9876543210123, 9000000)
49+
}

0 commit comments

Comments
 (0)