sum_of_primes.sf 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. #!/usr/bin/ruby
  2. # Sublinear algorithm for computing the sum of primes <= n, each prime raised to a fixed power j >= 0.
  3. # Algorithm from:
  4. # https://math.stackexchange.com/questions/1378286/find-the-sum-of-all-primes-smaller-than-a-big-number
  5. # PARI/GP program (for j = 1):
  6. # a(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;
  7. # Generalized PARI/GP program (for j >= 0):
  8. # a(n, j=2) = if(n <= 1, return(0)); my(r=sqrtint(n)); my(V=vector(r, k, n\k)); my(B=bernpol(j+1)); my(F(n)=(subst(B, x, n+1) - subst(B, 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]))); 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. func sum_of_primes(n, j=1) {
  10. return 0 if (n <= 1)
  11. var r = n.isqrt
  12. var V = (1..r -> map {|k| idiv(n,k) })
  13. V << range(V.last-1, 1, -1).to_a...
  14. var S = Hash(V.map{|k| (k, faulhaber(k,j)) }...)
  15. for p in (2..r) {
  16. S{p} > S{p-1} || next
  17. var sp = S{p-1}
  18. var p2 = p*p
  19. V.each {|v|
  20. break if (v < p2)
  21. S{v} -= ipow(p, j)*(S{idiv(v,p)} - sp)
  22. }
  23. }
  24. return S{n}-1
  25. }
  26. say sum_of_primes(1e6) #=> 37550402023
  27. say sum_of_primes(1e6, 2) #=> 24693298341834533
  28. assert_eq(
  29. 30.of { sum_of_primes(_) }
  30. 30.of { .sum_primes }
  31. )
  32. assert_eq(
  33. 30.of { sum_of_primes(_, 2) }
  34. 30.of { .primes.sum{.sqr} }
  35. )
  36. assert_eq(
  37. 30.of { sum_of_primes(_, 0) }
  38. 30.of { .prime_count }
  39. )
  40. __END__
  41. # A failed attempt at creating a sublinear method for computing the sum of primes <= n.
  42. # Based on the formulas:
  43. # a(n) = Sum_{k=1..n} Sum_{d|k} A008683(d) * A008472(k/d)
  44. # a(n) = Sum_{k=1..n} k*Sum_{d|k} mu(d) * omega(k/d)
  45. # a(n) = Sum_{k=1..n} floor(n/k) * Sum_{p prime | k} p*mu(k/p)
  46. # Which can be computed in sublinear time as:
  47. # a(n) = Sum_{k=1..floor(sqrt(n))} (A008472(k)*A002321(floor(n/k)) + A008683(k)*A024924(floor(n/k))) - A002321(floor(sqrt(n)))*A024924(floor(sqrt(n)))
  48. # a(n) = Sum_{k=1..m} (A008472(k)*A002321(floor(n/k)) + A008683(k)*A024924(floor(n/k))) - A002321(m)*A024924(m), where m = floor(sqrt(n)).
  49. # Where A024924(n) can be computed in sublinear time as (recursively, using the sum of primes function):
  50. # A024924(n) = Sum_{k=1..floor(sqrt(n))} (A061397(k)*floor(n/k) + A034387(floor(n/k))) - A034387(floor(sqrt(n)))*floor(sqrt(n))
  51. # See also:
  52. # https://oeis.org/A024924
  53. # https://oeis.org/A034387
  54. func sum_of_sopf(n) {
  55. dirichlet_sum(n,
  56. { .is_prime ? _ : 0 },
  57. { 1 },
  58. { .sum_primes }, # FIXME: remove the recursive definition
  59. { _ }
  60. )
  61. }
  62. func sum_of_primes(n) {
  63. dirichlet_sum(n,
  64. { .sopf },
  65. { .mu },
  66. (sum_of_sopf),
  67. { .mertens }
  68. )
  69. }
  70. func A137851_partial_sum(n) {
  71. dirichlet_sum(n,
  72. {.is_prime ? _ : 0},
  73. {.mu},
  74. {.sum_primes},
  75. {.mertens}
  76. )
  77. }
  78. func sum_of_primes_2(n) {
  79. dirichlet_sum(n,
  80. {|k| k.prime_divisors.sum {|p| p * mu(k/p) } },
  81. { 1 },
  82. (A137851_partial_sum),
  83. { _ },
  84. )
  85. }
  86. say sum_primes(1e5) #=> 454396537
  87. say sum_of_primes(1e5) #=> 454396537
  88. say sum_of_primes_2(1e5) #=> 454396537