mertens_function.pl 1.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. #!/usr/bin/perl
  2. # A simple implementation of a nice algorithm for computing the Mertens function:
  3. # M(x) = Sum_{k=1..n} moebius(k)
  4. # Algorithm due to Marc Deleglise and Joel Rivat:
  5. # https://projecteuclid.org/euclid.em/1047565447
  6. # This implementation is not particularly optimized.
  7. # See also:
  8. # https://oeis.org/A002321
  9. # https://oeis.org/A084237
  10. # https://en.wikipedia.org/wiki/Mertens_function
  11. # https://en.wikipedia.org/wiki/M%C3%B6bius_function
  12. use 5.016;
  13. use ntheory qw(sqrtint moebius);
  14. use experimental qw(signatures);
  15. sub mertens_function ($x) {
  16. my $u = sqrtint($x);
  17. my @M = (0);
  18. my @mu = moebius(0, $u); # list of Moebius(k) for k=0..floor(sqrt(n))
  19. # Partial sums of the Moebius function:
  20. # M[n] = Sum_{k=1..n} moebius(k)
  21. for my $i (1 .. $#mu) {
  22. $M[$i] += $M[$i - 1] + $mu[$i];
  23. }
  24. my $sum = $M[$u];
  25. foreach my $m (1 .. $u) {
  26. $mu[$m] || next;
  27. my $S1_t = 0;
  28. foreach my $n (int($u / $m) + 1 .. sqrtint(int($x / $m))) {
  29. $S1_t += $M[int($x / ($m * $n))];
  30. }
  31. my $S2_t = 0;
  32. foreach my $n (sqrtint(int($x / $m)) + 1 .. int($x / $m)) {
  33. $S2_t += $M[int($x / ($m * $n))];
  34. }
  35. $sum -= $mu[$m] * ($S1_t + $S2_t);
  36. }
  37. return $sum;
  38. }
  39. foreach my $n (1 .. 6) {
  40. say "M(10^$n) = ", mertens_function(10**$n);
  41. }
  42. __END__
  43. M(10^1) = -1
  44. M(10^2) = 1
  45. M(10^3) = 2
  46. M(10^4) = -23
  47. M(10^5) = -48
  48. M(10^6) = 212
  49. M(10^7) = 1037
  50. M(10^8) = 1928
  51. M(10^9) = -222