2
2
3
3
# Author: Daniel "Trizen" Șuteu
4
4
# Date: 09 November 2018
5
+ # Edit: 30 March 2025
5
6
# https://github.com/trizen
6
7
7
8
# A new generalized algorithm with O(sqrt(n)) complexity for computing the partial-sums of the `sigma_j(k)` function:
16
17
# https://en.wikipedia.org/wiki/Bernoulli_polynomials
17
18
# https://trizenx.blogspot.com/2018/11/partial-sums-of-arithmetical-functions.html
18
19
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) ;
25
22
use Math::AnyNum qw( faulhaber_sum bernoulli sum isqrt ipow) ;
26
23
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
28
25
29
26
my $s = isqrt($n );
30
27
my $u = int ($n / ($s + 1));
31
28
32
29
my $sum = 0;
33
30
34
31
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 ));
36
33
}
37
34
38
35
foreach my $k (1 .. $u ) {
@@ -42,15 +39,30 @@ ($n, $m = 1)
42
39
return $sum ;
43
40
}
44
41
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
46
58
47
59
my $s = isqrt($n );
48
60
my $u = int ($n / ($s + 1));
49
61
50
62
my $sum = 0;
51
63
52
64
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);
54
66
}
55
67
56
68
foreach my $k (1 .. $u ) {
@@ -61,7 +73,11 @@ ($n, $m = 1)
61
73
}
62
74
63
75
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
+ );
65
81
}
66
82
67
83
foreach my $m (0 .. 10) {
@@ -71,11 +87,13 @@ ($n, $m = 1)
71
87
my $t1 = sigma_partial_sum_test($n , $m );
72
88
my $t2 = sigma_partial_sum_faulhaber($n , $m );
73
89
my $t3 = sigma_partial_sum_bernoulli($n , $m );
90
+ my $t4 = sigma_partial_sum_dirichlet($n , $m );
74
91
75
92
say " Sum_{k=1..$n } sigma_$m (k) = $t2 " ;
76
93
77
94
die " error: $t1 != $t2 " if ($t1 != $t2 );
78
95
die " error: $t1 != $t3 " if ($t1 != $t3 );
96
+ die " error: $t1 != $t4 " if ($t1 != $t4 );
79
97
}
80
98
81
99
__END__
0 commit comments