Skip to content

Commit 66b2489

Browse files
committed
new file: Math/partial_sums_of_sigma0_function.pl
modified: Math/partial_sums_of_sigma_function.pl
1 parent 7e2b1df commit 66b2489

File tree

2 files changed

+92
-11
lines changed

2 files changed

+92
-11
lines changed
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#!/usr/bin/perl
2+
3+
# Author: Daniel "Trizen" Șuteu
4+
# Date: 09 November 2018
5+
# Edit: 30 March 2025
6+
# https://github.com/trizen
7+
8+
# Algorithm with O(sqrt(n)) complexity for computing the partial-sums of the `sigma_0(k)` function:
9+
# Sum_{k=1..n} sigma_0(k)
10+
11+
# See also:
12+
# https://oeis.org/A006218
13+
# https://en.wikipedia.org/wiki/Divisor_function
14+
# https://en.wikipedia.org/wiki/Faulhaber%27s_formula
15+
# https://en.wikipedia.org/wiki/Bernoulli_polynomials
16+
# https://trizenx.blogspot.com/2018/11/partial-sums-of-arithmetical-functions.html
17+
18+
use 5.036;
19+
20+
sub sigma0_partial_sum_faulhaber ($n) {
21+
22+
my $s = int(sqrt($n));
23+
my $sum = 0;
24+
25+
foreach my $k (1 .. $s) {
26+
$sum += 2 * int($n / $k);
27+
}
28+
29+
return ($sum - $s * $s);
30+
}
31+
32+
sub sigma0_partial_sum_test ($n) { # just for testing
33+
my $sum = 0;
34+
foreach my $k (1 .. $n) {
35+
$sum += int($n / $k);
36+
}
37+
return $sum;
38+
}
39+
40+
foreach my $m (0 .. 10) {
41+
42+
my $n = int(rand(1 << (2 * $m)));
43+
44+
my $t1 = sigma0_partial_sum_test($n);
45+
my $t2 = sigma0_partial_sum_faulhaber($n);
46+
47+
say "Sum_{k=1..$n} sigma_0(k) = $t2";
48+
49+
die "error: $t1 != $t2" if ($t1 != $t2);
50+
}
51+
52+
__END__
53+
Sum_{k=1..0} sigma_0(k) = 0
54+
Sum_{k=1..3} sigma_0(k) = 5
55+
Sum_{k=1..13} sigma_0(k) = 37
56+
Sum_{k=1..30} sigma_0(k) = 111
57+
Sum_{k=1..193} sigma_0(k) = 1049
58+
Sum_{k=1..51} sigma_0(k) = 211
59+
Sum_{k=1..2288} sigma_0(k) = 18059
60+
Sum_{k=1..15985} sigma_0(k) = 157208
61+
Sum_{k=1..10112} sigma_0(k) = 94818
62+
Sum_{k=1..152099} sigma_0(k) = 1838389
63+
Sum_{k=1..446108} sigma_0(k) = 5872025

Math/partial_sums_of_sigma_function.pl

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
# Author: Daniel "Trizen" Șuteu
44
# Date: 09 November 2018
5+
# Edit: 30 March 2025
56
# https://github.com/trizen
67

78
# A new generalized algorithm with O(sqrt(n)) complexity for computing the partial-sums of the `sigma_j(k)` function:
@@ -16,23 +17,19 @@
1617
# https://en.wikipedia.org/wiki/Bernoulli_polynomials
1718
# https://trizenx.blogspot.com/2018/11/partial-sums-of-arithmetical-functions.html
1819

19-
use 5.020;
20-
use strict;
21-
use warnings;
22-
23-
use ntheory qw(divisors);
24-
use experimental qw(signatures);
20+
use 5.036;
21+
use ntheory qw(divisors);
2522
use Math::AnyNum qw(faulhaber_sum bernoulli sum isqrt ipow);
2623

27-
sub sigma_partial_sum_faulhaber ($n, $m = 1) { # using Faulhaber's formula
24+
sub sigma_partial_sum_faulhaber ($n, $m = 1) { # using Faulhaber's formula
2825

2926
my $s = isqrt($n);
3027
my $u = int($n / ($s + 1));
3128

3229
my $sum = 0;
3330

3431
foreach my $k (1 .. $s) {
35-
$sum += $k * (faulhaber_sum(int($n/$k), $m) - faulhaber_sum(int($n/($k+1)), $m));
32+
$sum += $k * (faulhaber_sum(int($n / $k), $m) - faulhaber_sum(int($n / ($k + 1)), $m));
3633
}
3734

3835
foreach my $k (1 .. $u) {
@@ -42,15 +39,30 @@ ($n, $m = 1)
4239
return $sum;
4340
}
4441

45-
sub sigma_partial_sum_bernoulli ($n, $m = 1) { # using Bernoulli polynomials
42+
sub sigma_partial_sum_dirichlet ($n, $m = 1) { # using the Dirichlet hyperbola method
43+
44+
my $total = 0;
45+
my $s = isqrt($n);
46+
47+
for my $k (1 .. $s) {
48+
$total += faulhaber_sum(int($n / $k), $m);
49+
$total += ipow($k, $m) * int($n / $k);
50+
}
51+
52+
$total -= $s * faulhaber_sum($s, $m);
53+
54+
return $total;
55+
}
56+
57+
sub sigma_partial_sum_bernoulli ($n, $m = 1) { # using Bernoulli polynomials
4658

4759
my $s = isqrt($n);
4860
my $u = int($n / ($s + 1));
4961

5062
my $sum = 0;
5163

5264
foreach my $k (1 .. $s) {
53-
$sum += $k * (bernoulli($m+1, 1+int($n/$k)) - bernoulli($m+1, 1+int($n/($k+1)))) / ($m+1);
65+
$sum += $k * (bernoulli($m + 1, 1 + int($n / $k)) - bernoulli($m + 1, 1 + int($n / ($k + 1)))) / ($m + 1);
5466
}
5567

5668
foreach my $k (1 .. $u) {
@@ -61,7 +73,11 @@ ($n, $m = 1)
6173
}
6274

6375
sub sigma_partial_sum_test ($n, $m = 1) { # just for testing
64-
sum(map { sum(map { ipow($_, $m) } divisors($_)) } 1..$n);
76+
sum(
77+
map {
78+
sum(map { ipow($_, $m) } divisors($_))
79+
} 1 .. $n
80+
);
6581
}
6682

6783
foreach my $m (0 .. 10) {
@@ -71,11 +87,13 @@ ($n, $m = 1)
7187
my $t1 = sigma_partial_sum_test($n, $m);
7288
my $t2 = sigma_partial_sum_faulhaber($n, $m);
7389
my $t3 = sigma_partial_sum_bernoulli($n, $m);
90+
my $t4 = sigma_partial_sum_dirichlet($n, $m);
7491

7592
say "Sum_{k=1..$n} sigma_$m(k) = $t2";
7693

7794
die "error: $t1 != $t2" if ($t1 != $t2);
7895
die "error: $t1 != $t3" if ($t1 != $t3);
96+
die "error: $t1 != $t4" if ($t1 != $t4);
7997
}
8098

8199
__END__

0 commit comments

Comments
 (0)