sum_remainders.pl 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. #!/usr/bin/perl
  2. # Daniel "Trizen" Șuteu
  3. # Date: 10 March 2021
  4. # https://github.com/trizen
  5. # Let's consider the following function:
  6. # a(n,v) = Sum_{k=1..n} (v mod k)
  7. # The goal is to compute a(n,v) in sublinear time with respect to v.
  8. # Formula:
  9. # a(n,v) = n*v - A024916(v) + Sum_{k=n+1..v} k*floor(v/k).
  10. # Formula derived from:
  11. # a(n,v) = Sum_{k=1..n} (v - k*floor(v/k))
  12. # = n*v - Sum_{k=1..n} k*floor(v/k)
  13. # = n*v - Sum_{k=1..v} k*floor(v/k) + Sum_{k=n+1..v} k*floor(v/k)
  14. # Related problem:
  15. # Is there a sublinear formula for computing: Sum_{1<=k<=n, gcd(k,n)=1} k*floor(n/k) ?
  16. # See also:
  17. # https://oeis.org/A099726 -- Sum of remainders of the n-th prime mod k, for k = 1,2,3,...,n.
  18. # https://oeis.org/A340976 -- Sum_{1 < k < n} sigma(n) mod k, where sigma = A000203.
  19. # https://oeis.org/A340180 -- a(n) = Sum_{x in C(n)} (sigma(n) mod x), where C(n) is the set of numbers < n coprime to n, and sigma = A000203.
  20. use 5.020;
  21. use strict;
  22. use warnings;
  23. use ntheory qw(:all);
  24. use experimental qw(signatures);
  25. sub triangular ($n) { # Sum_{k=1..n} k = n-th triangular number
  26. divint(mulint($n, addint($n, 1)), 2);
  27. }
  28. sub sum_of_sigma ($n) { # A024916(n) = Sum_{k=1..n} sigma(k) = Sum_{k=1..n} k*floor(n/k)
  29. my $T = 0;
  30. my $s = sqrtint($n);
  31. foreach my $k (1 .. $s) {
  32. my $t = divint($n, $k);
  33. $T = vecsum($T, triangular($t), mulint($k, $t));
  34. }
  35. subint($T, mulint(triangular($s), $s));
  36. }
  37. sub g ($a, $b) { # g(a,b) = Sum_{k=a..b} k*floor(b/k)
  38. my $T = 0;
  39. while ($a <= $b) {
  40. my $t = divint($b, $a);
  41. my $u = divint($b, $t);
  42. $T = addint($T, mulint($t, subint(triangular($u), triangular(subint($a, 1)))));
  43. $a = addint($u, 1);
  44. }
  45. return $T;
  46. }
  47. sub sum_remainders ($n, $v) { # sub-linear formula
  48. addint(subint(mulint($n, $v), sum_of_sigma($v)), g(addint($n, 1), $v));
  49. }
  50. say sprintf "[%s]", join(', ', map { sum_remainders($_, nth_prime($_)) } 1 .. 20); #=> A099726
  51. say sprintf "[%s]", join(', ', map { sum_remainders($_ - 1, divisor_sum($_)) } 1 .. 20); #=> A340976
  52. foreach my $k (1 .. 8) {
  53. say("A099726(10^$k) = ", sum_remainders(powint(10, $k), nth_prime(powint(10, $k))));
  54. }
  55. __END__
  56. A099726(10^1) = 30
  57. A099726(10^2) = 2443
  58. A099726(10^3) = 248372
  59. A099726(10^4) = 25372801
  60. A099726(10^5) = 2437160078
  61. A099726(10^6) = 252670261459
  62. A099726(10^7) = 24690625139657
  63. A099726(10^8) = 2516604108737704