Calculating phi(k) for 1<k<N

前端 未结 9 1807
花落未央
花落未央 2020-12-04 20:08

Given a large N, I need to iterate through all phi(k) such that 1 < k < N :

  • time-complexity must be O(N logN)
  • memory-complexity mus
相关标签:
9条回答
  • 2020-12-04 21:08

    This factorizes N = PQ, where P & Q are prime.

    Works quite well, in Elixir or Erlang.

    You can try different generators for your pseudo-random sequence. x*x + 1 is commonly used.

    This line: defp f0(x, n), do: rem((x * x) + 1, n)

    Other possible points of improvement: better or alternative gcd, rem and abs functions

    defmodule Factorizer do
    
      def factorize(n) do
        t = System.system_time
    
        x = pollard(n, 2_000_000, 2_000_000)
        y = div(n, x)
        p = min(x, y)
        q = max(x, y)
    
        t = System.system_time - t
    
        IO.puts "
    Factorized #{n}: into [#{p} , #{q}] in #{t} μs
    "
    
        {p, q}
      end
    
      defp gcd(a,0), do: a
      defp gcd(a,b), do: gcd(b,rem(a,b))
    
      defp pollard(n, a, b) do
        a = f0(a, n)
        b = f0(f0(b, n), n)
    
        p = gcd(abs(b - a), n)
    
        case p > 1 do
          true  -> p
          false -> pollard(n, a, b)
        end
      end
    
      defp f0(x, n), do: rem((x * x) + 1, n)
    
    end
    
    0 讨论(0)
  • 2020-12-04 21:11

    Sieve the totients to n:

    (define (totients n)
      (let ((tots (make-vector (+ n 1))))
        (do ((i 0 (+ i 1))) ((< n i))
          (vector-set! tots i i))
        (do ((i 2 (+ i 1))) ((< n i) tots)
          (when (= i (vector-ref tots i))
            (vector-set! tots i (- i 1))
            (do ((j (+ i i) (+ i j))) ((< n j))
              (vector-set! tots j
                (* (vector-ref tots j) (- 1 (/ i)))))))))
    
    0 讨论(0)
  • 2020-12-04 21:12

    Here's an efficient python generator. The caveat is that it doesn't yield the results in order. It is based on https://stackoverflow.com/a/10110008/412529 .

    Memory complexity is O(log(N)) as it only has to store a list of prime factors for a single number at a time.

    CPU complexity is just barely superlinear, something like O(N log log N).

    def totientsbelow(N):
        allprimes = primesbelow(N+1)
        def rec(n, partialtot=1, min_p = 0):
            for p in allprimes:
                if p > n:
                    break
                # avoid double solutions such as (6, [2,3]), and (6, [3,2])
                if p < min_p: continue
                yield (p, p-1, [p])
                for t, tot2, r in rec(n//p, partialtot, min_p = p): # uses integer division
                    yield (t*p, tot2 * p if p == r[0] else tot2 * (p-1), [p] + r)
    
        for n, t, factors in rec(N):
            yield (n, t)
    
    0 讨论(0)
提交回复
热议问题