-
Notifications
You must be signed in to change notification settings - Fork 0
/
partial_sums_sublinear_formula.sf
60 lines (43 loc) · 1.28 KB
/
partial_sums_sublinear_formula.sf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#!/usr/bin/ruby
# Daniel "Trizen" Șuteu
# Date: 26 December 2018
# https://github.com/trizen
# Sublinear formula for computing partial sums.
# Let:
# R(n) = Sum_{k=1..n} f(k)
# S(n) = Sum_{k=1..n} g(k)
# Sum_{k=1..n} Sum_{d|k} f(d) * g(k/d) = Sum_{k=1..n} f(k) * S(floor(n/k))
# = Sum_{k=1..n} g(k) * R(floor(n/k))
# This partial can be computed in sub-linear time if R(n) and S(n) can be computed efficiently:
# Sum_{k=1..n} f(k) * S(floor(n/k)) = Sum_{k=1..floor(sqrt(n))} (R(floor(n/k)) - R(floor(n/(k+1)))) * S(k)
# + Sum_{k=1..floor(n/(1+floor(sqrt(n))))} f(k) * S(floor(n/k))
# See also:
# https://trizenx.blogspot.com/2018/11/partial-sums-of-arithmetical-functions.html
func g(n) { euler_phi(n) }
func f(n) { n }
func S(f, n) {
sum(1..n, {|k|
f(k)
})
}
func partial_sum(n) {
var s = n.isqrt
var u = floor(n/(1+s))
var total = 0
for k in (1..s) {
total += (S(f, floor(n/k)) - S(f, floor(n/(k+1))))*S(g, k)
}
for k in (1..u) {
total += (f(k) * S(g, floor(n/k)))
}
return total
}
func partial_sum_test(n) {
sum(1..n, {|k|
k.divisors.sum {|d|
f(d) * g(k/d)
}
})
}
say 20.of(partial_sum)
say 20.of(partial_sum_test)