2017-02-05 5 views
0

Существует сценарий python, который выполняет основную факторизацию. Это очень быстро и работает менее чем за секунду. Но есть некоторые функции для php, которые работают очень медленно. Требуется один параметр (длинное целое число), например и вычисление простой факторизации. Возвращает массив с 2 индексами. Результат для этого числа:Php prime factorization by python script

Array ([0] => 1233387599 [1] => 1036516703) 

питон скрипт: (getpq.py)

#!/usr/bin/env python 
from __future__ import print_function 
import prime 
import sys 
import json 

def eprint(*args, **kwargs): 
    print(*args, file=sys.stderr, **kwargs) 


pq = prime.primefactors(long(sys.argv[1])) 

sys.stdout.write(json.dumps(pq)) 
sys.stdout.flush() 

prime.py:

# NOTICE!!! This is copied from https://stackoverflow.com/questions/4643647/fast-prime-factorization-module 

import random 

def primesbelow(N): 
    # http://stackoverflow.com/questions/2068372/fastest-way-to-list-all-primes-below-n-in-python/3035188#3035188 
    #""" Input N>=6, Returns a list of primes, 2 <= p < N """ 
    correction = N % 6 > 1 
    N = {0:N, 1:N-1, 2:N+4, 3:N+3, 4:N+2, 5:N+1}[N%6] 
    sieve = [True] * (N // 3) 
    sieve[0] = False 
    for i in range(int(N ** .5) // 3 + 1): 
     if sieve[i]: 
      k = (3 * i + 1) | 1 
      sieve[k*k // 3::2*k] = [False] * ((N//6 - (k*k)//6 - 1)//k + 1) 
      sieve[(k*k + 4*k - 2*k*(i%2)) // 3::2*k] = [False] * ((N // 6 - (k*k + 4*k - 2*k*(i%2))//6 - 1) // k + 1) 
    return [2, 3] + [(3 * i + 1) | 1 for i in range(1, N//3 - correction) if sieve[i]] 

smallprimeset = set(primesbelow(100000)) 
_smallprimeset = 100000 

def isprime(n, precision=7): 
    # http://en.wikipedia.org/wiki/Miller-Rabin_primality_test#Algorithm_and_running_time 
    if n == 1 or n % 2 == 0: 
     return False 
    elif n < 1: 
     raise ValueError("Out of bounds, first argument must be > 0") 
    elif n < _smallprimeset: 
     return n in smallprimeset 


    d = n - 1 
    s = 0 
    while d % 2 == 0: 
     d //= 2 
     s += 1 

    for repeat in range(precision): 
     a = random.randrange(2, n - 2) 
     x = pow(a, d, n) 

     if x == 1 or x == n - 1: continue 

     for r in range(s - 1): 
      x = pow(x, 2, n) 
      if x == 1: return False 
      if x == n - 1: break 
     else: return False 

    return True 

# https://comeoncodeon.wordpress.com/2010/09/18/pollard-rho-brent-integer-factorization/ 
def pollard_brent(n): 
    if n % 2 == 0: return 2 
    if n % 3 == 0: return 3 

    y, c, m = random.randint(1, n-1), random.randint(1, n-1), random.randint(1, n-1) 

    g, r, q = 1, 1, 1 
    while g == 1: 
     x = y 
     for i in range(r): 
      y = (pow(y, 2, n) + c) % n 

     k = 0 
     while k < r and g==1: 
      ys = y 
      for i in range(min(m, r-k)): 
       y = (pow(y, 2, n) + c) % n 
       q = q * abs(x-y) % n 

      g = gcd(q, n) 
      k += m 
     r *= 2 
    if g == n: 
     while True: 
      ys = (pow(ys, 2, n) + c) % n 
      g = gcd(abs(x - ys), n) 
      if g > 1: 
       break 

    return g 

smallprimes = primesbelow(10000) # might seem low, but 1000*1000 = 1000000, so this will fully factor every composite < 1000000 
def primefactors(n, sort=False): 
    factors = [] 

    limit = int(n ** .5) + 1 
    for checker in smallprimes: 
     if checker > limit: break 
     while n % checker == 0: 
      factors.append(checker) 
      n //= checker 
      limit = int(n ** .5) + 1 
      if checker > limit: break 

    if n < 2: return factors 

    while n > 1: 
     if isprime(n): 
      factors.append(n) 
      break 
     factor = pollard_brent(n) # trial division did not fully factor, switch to pollard-brent 
     factors.extend(primefactors(factor)) # recurse to factor the not necessarily prime factor returned by pollard-brent 
     n //= factor 

    if sort: factors.sort() 

    return factors 

def factorization(n): 
    factors = {} 
    for p1 in primefactors(n): 
     try: 
      factors[p1] += 1 
     except KeyError: 
      factors[p1] = 1 
    return factors 

totients = {} 
def totient(n): 
    if n == 0: return 1 

    try: return totients[n] 
    except KeyError: pass 

    tot = 1 
    for p, exp in factorization(n).items(): 
     tot *= (p - 1) * p ** (exp - 1) 

    totients[n] = tot 
    return tot 

def gcd(a, b): 
    if a == b: return a 
    while b > 0: a, b = b, a % b 
    return a 

def lcm(a, b): 
    return abs(a * b) // gcd(a, b) 

Как я не знаю, питон , есть ли способ сделать это php?

Примечание: я нашел очень плохой алгоритм, реализованный в PHP, занимает около 600 секунд:

public function primefactor($num) { 
    $sqrt = sqrt($num); 
    for ($i = 2; $i <= $sqrt; $i++) { 
     if ($num % $i == 0) { 
      return array_merge($this->primefactor($num/$i), array($i)); 
     } 
    } 
    return array($num); 
} 
+0

Это работает как код python, но по мере его оптимизации на C это намного быстрее, но я не уверен, что есть лучший способ найти простые факторы, это общее решение. – Arman

+1

Факторинг - это обширная тема, которая была изучена в последние десятилетия. Существует множество алгоритмов различной степени сложности, которые были реализованы на большинстве распространенных языков программирования. Php, который вы даете, - это наивное разделение проб, которое является одним из худших возможных алгоритмов. Посмотрите на страницу Википедии по факторингу. Этот вопрос слишком широк для Stack Overflow (или вне темы, поскольку он может быть прочитан как запрос библиотеки php, аналогичной модулю Python 'prime'). –

ответ

1

Из источника Eсть. Вам нужно исследовать алгоритмы «простой факторизации». Если вы добавите PHP в качестве требования к поиску, вы можете найти код для более эффективных реализаций, чем приведенный выше метод грубой силы. Начало here.

Обратите внимание, что метод Python не показывает ничего об алгоритме: пакет премьер имеет встроенные алгоритмы, а также код, который вы дали просто вызывает это. Я читал, что пакет Python использует вероятностные методы (которые проверены на 100% точным с помощью примерно 300 цифр). Следите за ними, когда вы проводите исследования. Будут реализованы реализации на нескольких языках общего назначения; Я знаю, по крайней мере, Python, Java и C++.

+0

Да, я забыл упомянуть о ** пакете ** **. Я редактировал свой пост. Но о вашей упомянутой ссылке я нашел ее раньше, но max 'n' is * 2^31-1 = 2147483647 *, как упоминалось там. –

+0

Это ограничение от типа данных. Для вашего приложения вам нужно перейти на длинный целочисленный тип. – Prune