partial_sum_of_the_alternating_sum_of_divisors.sf 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. #!/usr/bin/ruby
  2. # Author: Trizen
  3. # Date: 11 May 2024
  4. # https://github.com/trizen
  5. # A sublinear formula for computing the partial sums alternating sum of divisors function (A206369), using Dirichlet's hyperbola method.
  6. # Formula:
  7. #
  8. # a(n) = Sum_{k=1..n} Sum_{d|k} (-1)^bigomega(k/d) * d
  9. # = Sum_{k=1..n} Sum_{d|k, d is a perfect square} phi(k/d)
  10. # = (1/2) * Sum_{k=1..n} (-1)^bigomega(k) * floor(n/k) * floor(n/k + 1)
  11. # = (Sum_{k=1..floor(n^(1/4))} S(floor(n/k^2))) + (Sum_{k=1..floor(sqrt(n))} phi(k) * floor(sqrt(floor(n/k)))) - S(floor(sqrt(n))) * floor(n^(1/4))
  12. #
  13. # where S(n) = Sum_{k=1..n} phi(k), where `phi` is the Euler totient function.
  14. # Example:
  15. # a(10^1) = 35
  16. # a(10^2) = 3311
  17. # a(10^3) = 329283
  18. # a(10^4) = 32900704
  19. # a(10^5) = 3289890783
  20. # a(10^6) = 328986877961
  21. # a(10^7) = 32898683779520
  22. # a(10^8) = 3289868149892131
  23. # a(10^9) = 328986813691207320
  24. # a(10^10) = 32898681337806276406
  25. # Asymptotic formula due to Tóth, 2013:
  26. # a(n) ~ (Pi^2/30) * n^2.
  27. # OEIS sequences:
  28. # https://oeis.org/A370905 -- Partial sums of the alternating sum of divisors function (A206369).
  29. # https://oeis.org/A002088 -- Sum of totient function: a(n) = Sum_{k=1..n} phi(k), cf. A000010.
  30. # See also:
  31. # https://en.wikipedia.org/wiki/Dirichlet_hyperbola_method
  32. # https://trizenx.blogspot.com/2018/11/partial-sums-of-arithmetical-functions.html
  33. func euler_totient_partial_sum (n) { # using Dirichlet's hyperbola method
  34. var total = 0
  35. var s = n.isqrt
  36. for k in (1..s) {
  37. total += k*mertens(idiv(n,k))
  38. }
  39. s.each_squarefree {|k|
  40. total += moebius(k)*faulhaber(idiv(n,k), 1)
  41. }
  42. total -= mertens(s)*faulhaber(s, 1)
  43. return total
  44. }
  45. func partial_sums_of_asod(n) { # sublinear complexity
  46. func S(n) {
  47. return euler_totient_partial_sum(n)
  48. }
  49. sum(1..n.iroot(4), {|k|
  50. S(floor(n / k**2))
  51. }) + sum(1..n.isqrt, {|k|
  52. phi(k) * isqrt(floor(n/k))
  53. }) - S(n.isqrt)*n.iroot(4)
  54. }
  55. func partial_sums_of_asod_test(n) { # just for testing
  56. sum(1..n, {|k| liouville(k) * faulhaber(idiv(n,k), 1) })
  57. }
  58. for m in (0..10) {
  59. var n = 1000.irand
  60. var t1 = partial_sums_of_asod(n)
  61. var t2 = partial_sums_of_asod_test(n)
  62. assert_eq(t1, t2, [n, t1, t2])
  63. say "Sum_{k=1..#{n}} Sum_{d|k} λ(k/d) * d = #{t2}"
  64. }