partial_sums_of_euler_totient_function.sf 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. #!/usr/bin/ruby
  2. # Author: Daniel "Trizen" Șuteu
  3. # Date: 20 November 2018
  4. # Edit: 06 June 2021
  5. # https://github.com/trizen
  6. # A new algorithm for computing the partial-sums of `ϕ(k)`, for `1 <= k <= n`:
  7. #
  8. # Sum_{k=1..n} phi(k)
  9. #
  10. # where phi(k) is the Euler totient function.
  11. # Based on the formula:
  12. # Sum_{k=1..n} phi(k) = (1/2)*Sum_{k=1..n} moebius(k) * floor(n/k) * floor(1+n/k)
  13. # Example:
  14. # a(10^1) = 32
  15. # a(10^2) = 3044
  16. # a(10^3) = 304192
  17. # a(10^4) = 30397486
  18. # a(10^5) = 3039650754
  19. # a(10^6) = 303963552392
  20. # a(10^7) = 30396356427242
  21. # a(10^8) = 3039635516365908
  22. # a(10^9) = 303963551173008414
  23. # This algorithm can be improved.
  24. # See also:
  25. # https://oeis.org/A002088
  26. # https://oeis.org/A064018
  27. # https://en.wikipedia.org/wiki/Mertens_function
  28. # https://en.wikipedia.org/wiki/M%C3%B6bius_function
  29. # https://en.wikipedia.org/wiki/Euler%27s_totient_function
  30. # https://en.wikipedia.org/wiki/Dirichlet_hyperbola_method
  31. # https://trizenx.blogspot.com/2018/08/interesting-formulas-and-exercises-in.html
  32. func euler_totient_partial_sum (n) {
  33. var total = 0
  34. var s = n.isqrt
  35. var u = idiv(n, s+1)
  36. var prev = mertens(n)
  37. for k in (1..s) {
  38. with (mertens(idiv(n, k+1))) {|curr|
  39. total += ((prev - curr) * faulhaber(k, 1))
  40. prev = curr
  41. }
  42. }
  43. u.each_squarefree {|k|
  44. total += (moebius(k) * faulhaber(idiv(n,k), 1))
  45. }
  46. return total
  47. }
  48. func euler_totient_partial_sum_2 (n) { # using Dirichlet's hyperbola method
  49. var total = 0
  50. var s = n.isqrt
  51. for k in (1..s) {
  52. total += k*mertens(idiv(n,k))
  53. }
  54. s.each_squarefree {|k|
  55. total += moebius(k)*faulhaber(idiv(n,k), 1)
  56. }
  57. total -= mertens(s)*faulhaber(s, 1)
  58. return total
  59. }
  60. func euler_totient_partial_sum_test (n) { # just for testing
  61. 1..n -> sum { .euler_phi }
  62. }
  63. for m in (0 .. 10) {
  64. var n = 10000.irand
  65. var t1 = euler_totient_partial_sum(n)
  66. var t2 = euler_totient_partial_sum_2(n)
  67. var t3 = euler_totient_partial_sum_test(n)
  68. assert_eq(t1, t2)
  69. assert_eq(t1, t3)
  70. say "Sum_{k=1..#{n}} phi(k) = #{t1}"
  71. }
  72. __END__
  73. Sum_{k=1..6000} phi(k) = 10943164
  74. Sum_{k=1..9647} phi(k) = 28292296
  75. Sum_{k=1..1767} phi(k) = 949684
  76. Sum_{k=1..4643} phi(k) = 6554816
  77. Sum_{k=1..5814} phi(k) = 10276132
  78. Sum_{k=1..3120} phi(k) = 2959328
  79. Sum_{k=1..1998} phi(k) = 1213790
  80. Sum_{k=1..1269} phi(k) = 489854
  81. Sum_{k=1..1298} phi(k) = 512500
  82. Sum_{k=1..6555} phi(k) = 13062444
  83. Sum_{k=1..1101} phi(k) = 368850