v2 / vlib / math / big / bench / bench_edigits.v
85 lines · 78 sloc · 1.79 KB · b7b2fe14a868efb1727975537ad88deccf3fde7b
Raw
1module main
2
3import benchmark
4import math
5import math.big
6import os
7import strconv
8
9// Regression benchmark for issue #21319.
10// It mirrors the external edigits workload without printing every line,
11// so the timing stays focused on `math.big`.
12const default_n = 250_001
13const one = big.one_int
14const ten = big.c10
15
16fn main() {
17 mut n := default_n
18 if os.args.len > 1 {
19 n = strconv.atoi(os.args[1]) or { default_n }
20 }
21 mut clock := benchmark.start()
22 k := binary_search(n)
23 clock.measure('k=${k}')
24 mut p, q := sum_terms(0, k - 1)
25 clock.measure('sum_terms p.bit_len=${p.bit_len()} q.bit_len=${q.bit_len()}')
26 p += q
27 a := ten.pow(u32(n - 1))
28 clock.measure('pow 10^${n - 1}')
29 answer := p * a / q
30 clock.measure('division answer.bit_len=${answer.bit_len()}')
31 s := answer.str()
32 clock.measure('str digits=${s.len}')
33 if s.len != n {
34 eprintln('unexpected digit count: got ${s.len}, want ${n}')
35 return
36 }
37 println(last_line(s, n))
38}
39
40fn sum_terms(a int, b int) (big.Integer, big.Integer) {
41 if b == a + 1 {
42 return one, big.integer_from_int(b)
43 }
44 mid := (a + b) / 2
45 p_left, q_left := sum_terms(a, mid)
46 p_right, q_right := sum_terms(mid, b)
47 return p_left * q_right + p_right, q_left * q_right
48}
49
50fn binary_search(n int) int {
51 mut a := 0
52 mut b := 1
53 for !test_k(n, b) {
54 a = b
55 b *= 2
56 }
57 for b - a > 1 {
58 m := (a + b) / 2
59 if test_k(n, m) {
60 b = m
61 } else {
62 a = m
63 }
64 }
65 return b
66}
67
68fn test_k(n int, k int) bool {
69 if k < 0 {
70 return false
71 }
72 ln_k_factorial := k * (math.log(k) - 1) + 0.5 * math.log(math.tau)
73 log_10_k_factorial := ln_k_factorial / math.ln10
74 return log_10_k_factorial >= n + 50
75}
76
77fn last_line(s string, n int) string {
78 chunk_len := if n % 10 == 0 { 10 } else { n % 10 }
79 start := n - chunk_len
80 mut line := s[start..n]
81 for line.len < 10 {
82 line += ' '
83 }
84 return '${line}\t:${n}'
85}
86