Skip to content
60 changes: 39 additions & 21 deletions bench/algorithm/binarytrees/1.v
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,48 @@ import strconv
import os

struct Node {
left &Node
right &Node
left &Node = unsafe { nil }
right &Node = unsafe { nil }
}

fn check(node &Node) int {
mut ret := 1
unsafe {
if node.left != 0 {
ret += check(node.left)
}
if node.right != 0 {
ret += check(node.right)
}
if node.left != nil {
ret += check(node.left)
}
if node.right != nil {
ret += check(node.right)
}
return ret
}

fn create(n int) &Node {
if n == 0 {
return &Node{
left: unsafe { nil }
right: unsafe { nil }
}
// Nodes are carved out of one block per tree; the block is reset and reused
// between trees of the same depth.
struct Arena {
mut:
nodes []Node
pos int
}

fn new_arena(depth int) Arena {
return Arena{
nodes: []Node{len: (1 << (depth + 1)) - 1}
}
return &Node{
left: create(n - 1)
right: create(n - 1)
}

@[direct_array_access]
fn (mut a Arena) create(depth int) &Node {
i := a.pos
a.pos++
a.nodes[i] = if depth == 0 {
Node{}
} else {
Node{
left: a.create(depth - 1)
right: a.create(depth - 1)
}
}
return unsafe { &a.nodes[i] }
}

const min_depth = 4
Expand All @@ -41,20 +55,24 @@ fn main() {
}

stretch_depth := max_depth + 1
stretch_tree := create(stretch_depth)
mut stretch_arena := new_arena(stretch_depth)
stretch_tree := stretch_arena.create(stretch_depth)
println('stretch tree of depth ${stretch_depth}\t check: ${check(stretch_tree)}')

long_lived_tree := create(max_depth)
mut long_lived_arena := new_arena(max_depth)
long_lived_tree := long_lived_arena.create(max_depth)

n_results := (max_depth - min_depth) / 2 + 1

for i in 0 .. n_results {
depth := i * 2 + min_depth
n := 1 << (max_depth - depth + min_depth)

mut arena := new_arena(depth)
mut check_result := 0
for _ in 0 .. n {
node := create(depth)
arena.pos = 0
node := arena.create(depth)
check_result += check(node)
}

Expand Down
49 changes: 45 additions & 4 deletions bench/algorithm/edigits/1.v
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,15 @@ module main
import os
import strconv
import math.big
import strings
import math

const one = big.integer_from_int(1)
const ten = big.integer_from_int(10)

// Digits per leaf of `write_dec`; 10^leaf_digits - 1 still fits in an u32.
const leaf_digits = 9

fn main() {
mut n := 27
if os.args.len > 1 {
Expand All @@ -17,20 +21,57 @@ fn main() {
k := binary_search(n)
mut p, q := sum_terms(0, k - 1)
p += q
mut a := ten.pow(u32(n - 1))
a := ten.pow(u32(n - 1))
answer := p * a / q
s := answer.str()
s := decimal_str(answer, n)
mut sb := strings.new_builder(n / 10 * 24)
for i := 0; i < n; i += 10 {
if i + 10 <= n {
println('${s[i..i + 10]}\t:${i + 10}')
sb.writeln('${s[i..i + 10]}\t:${i + 10}')
} else {
mut line := s[i..n]
for _ in 0 .. (10 - n % 10) {
line = '${line} '
}
print('${line}\t:${n}')
sb.write_string('${line}\t:${n}')
}
}
print(sb.str())
}

// Renders `x`, which is known to have exactly `n` decimal digits, by
// recursively halving it against precomputed powers of ten.
fn decimal_str(x big.Integer, n int) string {
mut pows := [ten.pow(leaf_digits)]
mut width := leaf_digits
for width < n {
pows << pows.last() * pows.last()
width *= 2
}
mut buf := []u8{len: width}
write_dec(x, pows.len - 1, pows, mut buf)
return buf[width - n..].bytestr()
}

fn write_dec(x big.Integer, level int, pows []big.Integer, mut buf []u8) {
if x.signum == 0 {
for i in 0 .. buf.len {
buf[i] = `0`
}
return
}
if level == 0 {
mut v := u32(x.int())
for i := leaf_digits - 1; i >= 0; i-- {
buf[i] = u8(`0` + v % 10)
v /= 10
}
return
}
hi, lo := x.div_mod(pows[level - 1])
half := leaf_digits << (level - 1)
write_dec(hi, level - 1, pows, mut buf[..half])
write_dec(lo, level - 1, pows, mut buf[half..])
}

fn sum_terms(a int, b int) (big.Integer, big.Integer) {
Expand Down
142 changes: 142 additions & 0 deletions bench/algorithm/fannkuch-redux/1-m.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
module main

import os
import runtime
import strconv

const max_n = 16

struct Result {
checksum int
max_flips int
}

fn main() {
mut n := 10
if os.args.len == 2 {
n = strconv.atoi(os.args[1]) or { 10 }
}

total := factorials(n)[n]

mut nthreads := runtime.nr_cpus()
if nthreads < 1 {
nthreads = 1
}
// Chunks must start on an even index: the checksum's sign derives from it.
nchunks := i64(nthreads) * 4
mut chunk := (total + nchunks - 1) / nchunks
chunk += chunk % 2

mut workers := []thread Result{}
for lo := i64(0); lo < total; lo += chunk {
hi := if lo + chunk < total { lo + chunk } else { total }
workers << spawn fannkuchredux(n, lo, hi)
}
results := workers.wait()

mut checksum := 0
mut max_flips := 0
for r in results {
checksum += r.checksum
if r.max_flips > max_flips {
max_flips = r.max_flips
}
}

println('${checksum}\nPfannkuchen(${n}) = ${max_flips}')
}

fn factorials(n int) []i64 {
mut fact := []i64{len: n + 1}
fact[0] = 1
for i in 1 .. n + 1 {
fact[i] = fact[i - 1] * i
}
return fact
}

// Walks permutations [idx_min, idx_max), seeking to the start once and then
// advancing incrementally, and skipping the flip count when p[0] is 0.
fn fannkuchredux(n int, idx_min i64, idx_max i64) Result {
fact := factorials(n)
mut p := [max_n]int{}
mut pp := [max_n]int{}
mut count := [max_n]int{}

for i in 0 .. n {
p[i] = i
}
mut seek := idx_min
for i := n - 1; i > 0; i-- {
d := int(seek / fact[i])
count[i] = d
seek %= fact[i]
pp = p
for j in 0 .. i + 1 {
p[j] = if j + d <= i { pp[j + d] } else { pp[j + d - i - 1] }
}
}

mut max_flips := 1
mut checksum := 0
mut sign := true

for idx := idx_min; true; idx++ {
first := p[0]
if first != 0 {
mut flips := 1
if p[first] != 0 {
pp = p
mut p0 := first
for {
flips++
for i, j := 1, p0 - 1; i < j; i, j = i + 1, j - 1 {
pp[i], pp[j] = pp[j], pp[i]
}
t := pp[p0]
pp[p0] = p0
p0 = t
if pp[p0] == 0 {
break
}
}
}
if max_flips < flips {
max_flips = flips
}
if sign {
checksum += flips
} else {
checksum -= flips
}
}

if idx + 1 == idx_max {
break
}

if sign {
p[0], p[1] = p[1], first
sign = false
} else {
p[1], p[2] = p[2], p[1]
sign = true
mut f := first
for k := 2; true; k++ {
count[k]++
if count[k] <= k {
break
}
count[k] = 0
for j in 0 .. k + 1 {
p[j] = p[j + 1]
}
p[k + 1] = f
f = p[0]
}
}
}

return Result{checksum, max_flips}
}
Loading