mertens_function.sf 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. #!/usr/bin/ruby
  2. # Daniel "Trizen" Șuteu
  3. # Date: 04 February 2019
  4. # https://github.com/trizen
  5. # A sublinear algorithm for computing the Mertens function (partial sums of the Möbius function).
  6. # Defined as:
  7. #
  8. # M(n) = Sum_{k=1..n} μ(k)
  9. #
  10. # where μ(k) is the Möbius function.
  11. # Example:
  12. # M(10^1) = -1
  13. # M(10^2) = 1
  14. # M(10^3) = 2
  15. # M(10^4) = -23
  16. # M(10^5) = -48
  17. # M(10^6) = 212
  18. # M(10^7) = 1037
  19. # M(10^8) = 1928
  20. # M(10^9) = -222
  21. # OEIS sequences:
  22. # https://oeis.org/A008683 -- Möbius (or Moebius) function mu(n).
  23. # https://oeis.org/A084237 -- M(10^n), where M(n) is Mertens's function.
  24. # See also:
  25. # https://en.wikipedia.org/wiki/Mertens_function
  26. # https://en.wikipedia.org/wiki/M%C3%B6bius_function
  27. func mertens_function(n) {
  28. var lookup_size = (2 * n.iroot(3)**2)
  29. var moebius_lookup = ::moebius(0, lookup_size)
  30. var mertens_lookup = [0]
  31. for k in (1..lookup_size) {
  32. mertens_lookup[k] = (mertens_lookup[k-1] + moebius_lookup[k])
  33. }
  34. var cache = Hash()
  35. func (n) {
  36. if (n <= lookup_size) {
  37. return mertens_lookup[n]
  38. }
  39. if (cache.has(n)) {
  40. return cache{n}
  41. }
  42. var s = n.isqrt
  43. var M = 1
  44. for k in (2 .. floor(n/(s+1))) {
  45. M -= __FUNC__(floor(n/k))
  46. }
  47. for k in (1..s) {
  48. M -= (mertens_lookup[k] * (floor(n/k) - floor(n/(k+1))))
  49. }
  50. cache{n} = M
  51. }(n)
  52. }
  53. for n in (1 .. 6) { # takes ~1.3 seconds
  54. say ("M(10^#{n}) = ", mertens_function(10**n))
  55. }