partial_sums_of_sigma_function_times_k.pl 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. #!/usr/bin/perl
  2. # Author: Daniel "Trizen" Șuteu
  3. # Date: 10 November 2018
  4. # https://github.com/trizen
  5. # A new generalized algorithm with O(sqrt(n)) complexity for computing the partial-sums of `k * sigma_j(k)`, for `1 <= k <= n`:
  6. #
  7. # Sum_{k=1..n} k * sigma_j(k)
  8. #
  9. # for any integer j >= 0.
  10. # Example: `a(n) = Sum_{k=1..n} k * sigma(k)`
  11. # a(10^1) = 622
  12. # a(10^2) = 558275
  13. # a(10^3) = 549175530
  14. # a(10^4) = 548429473046
  15. # a(10^5) = 548320905633448
  16. # a(10^6) = 548312690631798482
  17. # a(10^7) = 548311465139943768941
  18. # a(10^8) = 548311366911386862908968
  19. # a(10^9) = 548311356554322895313137239
  20. # a(10^10) = 548311355740964925044531454428
  21. # For m>=0 and j>=1, we have the following asymptotic formula:
  22. # Sum_{k=1..n} k^m * sigma_j(k) ~ zeta(j+1)/(j+m+1) * n^(j+m+1)
  23. # See also:
  24. # https://en.wikipedia.org/wiki/Divisor_function
  25. # https://en.wikipedia.org/wiki/Faulhaber%27s_formula
  26. # https://en.wikipedia.org/wiki/Bernoulli_polynomials
  27. # https://trizenx.blogspot.com/2018/11/partial-sums-of-arithmetical-functions.html
  28. use 5.020;
  29. use strict;
  30. use warnings;
  31. use ntheory qw(divisors);
  32. use experimental qw(signatures);
  33. use Math::AnyNum qw(faulhaber_sum sum isqrt ipow);
  34. sub sigma_partial_sum($n, $m) { # O(sqrt(n)) complexity
  35. my $total = 0;
  36. my $s = isqrt($n);
  37. my $u = int($n / ($s + 1));
  38. for my $k (1 .. $s) {
  39. $total += $k*($k+1) * (faulhaber_sum(int($n/$k), $m+1) - faulhaber_sum(int($n/($k+1)), $m+1));
  40. }
  41. for my $k (1 .. $u) {
  42. $total += ipow($k, $m+1) * int($n/$k) * (1 + int($n/$k));
  43. }
  44. return $total/2;
  45. }
  46. sub sigma_partial_sum_test($n, $m) { # just for testing
  47. sum(map { $_ * sum(map { ipow($_, $m) } divisors($_)) } 1..$n);
  48. }
  49. for my $m (0..10) {
  50. my $n = int(rand(1000));
  51. my $t1 = sigma_partial_sum($n, $m);
  52. my $t2 = sigma_partial_sum_test($n, $m);
  53. die "error: $t1 != $t2" if ($t1 != $t2);
  54. say "Sum_{k=1..$n} k * σ_$m(k) = $t2"
  55. }
  56. __END__
  57. Sum_{k=1..649} k * σ_0(k) = 1505437
  58. Sum_{k=1..184} k * σ_1(k) = 3442689
  59. Sum_{k=1..156} k * σ_2(k) = 180861250
  60. Sum_{k=1..781} k * σ_3(k) = 63090289257686
  61. Sum_{k=1..822} k * σ_4(k) = 53514505511600484
  62. Sum_{k=1..982} k * σ_5(k) = 128445772086331164364
  63. Sum_{k=1..742} k * σ_6(k) = 11644176895188820029668
  64. Sum_{k=1..837} k * σ_7(k) = 22614022054863154308526282
  65. Sum_{k=1..355} k * σ_8(k) = 3230297764819153302018985
  66. Sum_{k=1..837} k * σ_9(k) = 12937980446016909148074821860258
  67. Sum_{k=1..699} k * σ_10(k) = 1144140317656849776081892799180303