sum_of_prime_powers.sf 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. #!/usr/bin/ruby
  2. # Sublinear algorithm for computing the sum of prime powers <= n, based on the sublinear algorithm for computing the sum of primes <= n.
  3. # See also:
  4. # https://oeis.org/A074793
  5. # PARI/GP program:
  6. #`(
  7. f(n) = if(n <= 1, return(0)); my(r=sqrtint(n)); my(V=vector(r, k, n\k)); my(L=n\r-1); V=concat(V, vector(L, k, L-k+1)); my(T=vector(#V, k, V[k]*(V[k]+1)\2)); my(S=Map(matrix(#V, 2, x, y, if(y==1, V[x], T[x])))); forprime(p=2, r, my(sp=mapget(S, p-1), p2=p*p); for(k=1, #V, if(V[k] < p2, break); mapput(S, V[k], mapget(S, V[k]) - p*(mapget(S, V[k]\p) - sp)))); mapget(S, n)-1;
  8. g(n, j=2) = if(n <= 1, return(0)); my(r=sqrtint(n)); my(V=vector(r, k, n\k)); my(F(n, j)=(subst(bernpol(j+1), x, n+1) - subst(bernpol(j+1), x, 1)) / (j+1)); my(L=n\r-1); V=concat(V, vector(L, k, L-k+1)); my(T=vector(#V, k, F(V[k], j))); my(S=Map(matrix(#V, 2, x, y, if(y==1, V[x], T[x])))); forprime(p=2, r, my(sp=mapget(S, p-1), p2=p*p); for(k=1, #V, if(V[k] < p2, break); mapput(S, V[k], mapget(S, V[k]) - p^j*(mapget(S, V[k]\p) - sp)))); mapget(S, n)-1;
  9. a(n) = my(s=0); forprime(p=2, sqrtnint(n,3), s += (p^(logint(n, p)+1) - 1)/(p-1) - p*p - p - 1); f(n) + g(sqrtint(n)) + s;
  10. b(n) = my(s=0); forprime(p=2, sqrtint(n), s += (p^(logint(n, p)+1) - 1)/(p-1) - p - 1); f(n) + s;
  11. c(n) = sum(k=1, logint(n,2), g(sqrtnint(n,k), k));
  12. )
  13. func sum_of_primes(n, j=1) { # Sum_{p prime <= n} p^k
  14. return n.sum_primes if (j == 1) # optimization
  15. return 0 if (n <= 1)
  16. var r = n.isqrt
  17. var V = (1..r -> map {|k| idiv(n,k) })
  18. V << range(V.last-1, 1, -1).to_a...
  19. var S = Hash(V.map{|k| (k, faulhaber_sum(k,j)) }...)
  20. for p in (2..r) {
  21. S{p} > S{p-1} || next
  22. var sp = S{p-1}
  23. var p2 = p*p
  24. V.each {|v|
  25. break if (v < p2)
  26. S{v} -= ipow(p,j)*(S{idiv(v,p)} - sp)
  27. }
  28. }
  29. return S{n}-1
  30. }
  31. func sum_of_prime_powers(n) {
  32. # a(n) = Sum_{p prime <= n} p
  33. # b(n) = Sum_{p prime <= n^(1/2)} p^2
  34. # c(n) = Sum_{p prime <= n^(1/3)} f(p)
  35. # sum_of_prime_powers(n) = a(n) + b(n) + c(n)
  36. var ps1 = sum_of_primes(n)
  37. var ps2 = sum_of_primes(n.isqrt, 2)
  38. # f(p) = (Sum_{k=1..floor(log_p(n))} p^k) - p^2 - p
  39. # = (p^(1+floor(log_p(n))) - 1)/(p-1) - p^2 - p - 1
  40. var ps3 = n.icbrt.primes.sum {|p|
  41. (ipow(p, n.ilog(p)+1) - 1)/(p-1) - p*p - p - 1
  42. }
  43. ps1 + ps2 + ps3
  44. }
  45. func sum_of_prime_powers_2(n) {
  46. # a(n) = Sum_{p prime <= n} p
  47. # b(n) = Sum_{p prime <= n^(1/2)} f(p)
  48. # sum_of_prime_powers(n) = a(n) + b(n)
  49. var ps1 = sum_of_primes(n)
  50. # f(p) = (Sum_{k=1..floor(log_p(n))} p^k) - p
  51. # = (p^(1+floor(log_p(n))) - 1)/(p-1) - p - 1
  52. var ps2 = 0
  53. n.isqrt.each_prime {|p|
  54. ps2 += ((ipow(p, n.ilog(p)+1) - 1)/(p-1) - p - 1)
  55. }
  56. ps1 + ps2
  57. }
  58. func sum_of_prime_powers_3(n) {
  59. # a(n) = Sum_{k=1..floor(log_2(n))} Sum_{p prime <= n^(1/k)} p^k.
  60. sum(1..n.ilog2, {|k|
  61. sum_of_primes(n.iroot(k), k)
  62. })
  63. }
  64. say sum_of_prime_powers(1e5) #=> 457028152
  65. say sum_of_prime_powers(43**3) #=> 294752679
  66. for k in (1..100) {
  67. var n = 1e3.irand
  68. var x = sum_of_prime_powers(n)
  69. var y = sum_of_prime_powers_2(n)
  70. var z = sum_of_prime_powers_3(n)
  71. var w = n.prime_powers.sum
  72. assert_eq(x,y)
  73. assert_eq(x,z)
  74. assert_eq(x,w)
  75. }