Найти наибольший делитель N, который меньше sqrt(N)

на самом деле, учитывая N a (возможно,очень большое) четное целое число, я хочу найти N = F * R, где gcd(F, R) = 1, F>R и F как можно меньше (так как я буду полностью факторинг F). Суть проблемы заключается в нахождении наибольшего делителя R, где R

например, N=36 должно давать F=9 и R=4. Обратите внимание, что R не обязательно является простым или первичной мощностью. Обратите внимание, что я не факторинг N. единственное ограничение на F и R заключается в том, что они относительно главный.

Это моя быстрая и наивная версия, которая работает:

def factor_partial(N):
    for R in xrange(int(math.sqrt(N)),1,-1):
        if N%R == 0 and gcd(R,N/R) == 1:
            return N/R, R

другой способ, который я себе представляю, это найти делители в возрастающем порядке и удалить любые кратные недивизоры по пути. Что-то вроде:

def factor_partial(N):
    i = range(2, int(sqrt(N)) + 1)
    while i:
        if N % i[0] != 0:
            remove_multiples(i, i[0]) #without removing i[0]
        else:
            if gcd(i[0], N/i[0]) == 1:
                R = i[0]
        i.pop(0) #remove i[0]

    return N/R, R

Я думаю, что это будет медленно и много памяти, но, возможно, если i вместо этого генератор он может быть эффективным. Я не часто пользовался генераторами.

могу ли я улучшить первую версию? Есть вторая версия жизнеспособна (как бы я это сделал)? Есть ли совершенно другой метод, который лучше?

поиск ответов в python, c или псевдокоде.


Это для проекта для класса по теории чисел. Я реализую тест на примитивность, основанный на Поклингтоне. Хотя мне нужен алгоритм факторизации, мы его не изучали, и я, вероятно, не буду использовать такой, как квадратичное сито, которое выходит за рамки моего класс. Я ищу конкретную помощь с поставленным вопросом.

3 ответов


Википедия имеет хороший список алгоритмов факторинга:http://en.wikipedia.org/wiki/Integer_factorization#Factoring_algorithms

ваш второй подход эффективно использует сито и имеет хорошее свойство быстро уменьшить проблему, когда N кратно небольшие премьер. Код можно улучшить, зацикливаясь на простых числах, а не на всех возможных делителях для 2..sqrt (n).

кроме того, вы можете начать с тест на примитивность, чтобы вы знали, что N является составным перед выполнением дополнительной работы.

в вашей записке говорится, что вы не факторинг N, но проблемы связаны. Поиск F и R суммы для изучения неперекрывающихся комбинаций простых факторов N.

в случае N==36 премьер-факторизации N и 2, 2, 3, 3. Факторы F и R должны включать все из них (так что F*R==N) и не может быть перекрытия (так что GCD(F,R)==1). Поэтому 4 и 9 появляются немедленно.

более поучительным примером может быть N==23256. Его факторизация 2,2,2,3,3,17,19. Поскольку не может быть перекрытия между F и R, каждая основная база может входить только в одно из двух ведер (т. е. вы либо получаете все двойки, либо ни одного из них). Таким образом, мы можем сгруппировать факторы в 8,9,17,19. Чтобы найти R, нам нужна комбинация тех факторов, которые так же велики, как возможно, но ниже 152.49, квадратный корень из 23256. Наш выбор {8}, {9}, {8,9}, {8,17}, {8,19}. Самый большой из них -8*19, которая составляет 152. Соответствующее F и 17*19 или 153.

на выбор перечисленные выше, рассчитываются как [choice for choice in powerset([8,9,17,19]) if prod(choice) < math.sqrt(N)].

таким образом, вся программа в значительной степени сводится к следующему:

prime_factors = factorize(N)      # [2,2,2,3,3,17,19]
clusters = [p**e for p, e in collections.Counter(prime_factors).items()]  # [8,9,17,19]
R = max(prod(group) for group in powerset(clusters) if prod(group) < math.sqrt(N))
F = N // R

на powerset поиск можно сделать быстрее, обрезая поколение наборов всякий раз, когда они превышают квадратный корень на N.

имейте в виду, что факторизация является вычислительно дорогой и powersets растут очень быстро, но это, вероятно, гораздо меньше работы, чем запуск, что оригинальный алгоритм, который делает много делений, начиная с квадратного корня N и работать вниз.


могли бы вы получить простую факторизацию N, а затем найти наибольшую комбинацию продуктов всех простых факторов, которая меньше sqrt(N)?

например, с 36 он обнаружил бы, что простая факторизация 2*2*3*3 - ... Затем вы попробуете все различные комбинации простых чисел:

2 = 2
3 = 3
2*2 = 4
2*3 = 6
3*3 = 9
2*2*3 = 12
2*3*3 = 18
2*2*3*3 = 36

а вы знаете, что это все факторы 36, поэтому вы найдете самый большой такой, что он меньше sqrt(36), который оказывается 4.

однако я действительно не вижу, как это может быть намного быстрее, чем просто сделать вашу первую версию, если у вас уже есть существующий список простых чисел или простых факторизаций, или какой-то удивительный простой факторизации algo, или вы делаете все это с чрезвычайно большими числами.

но даже тогда (назад к первой версии raving) O (sqrt (n)) является довольно быстрая среда выполнения и требует только O (1) памяти, поэтому на самом деле первый algo может быть просто способом. Я не вижу, как это будет медленно, особенно в C на современном компьютере.


def factor_partial(N):
    R = int(sqrt(float(N)))
    sieve = [1, 1] + [0] * (R-1)
    for i in xrange(2, R) :
        if sieve[i]==0 :
            j=i*i;
            while j<=R :
                sieve[j]=1
                j = j + i
    primes = [i for i in xrange(R+1) if sieve[i]==0]

    saveN = N
    primepower_divisors = []
    for i in primes :
        if N%i == 0 :
            term = 1
            while N%i == 0 :
                term = term * i
                N = N / i
            primepower_divisors = primepower_divisors + [term]
            if N==1 : break

    largecoprime_divisors = [1]
    for i in primepower_divisors :
        for j in largecoprime_divisors :
            largecoprime_divisors = largecoprime_divisors + [i*j]

    F = min([i for i in largecoprime_divisors if i>R])
    return F, saveN/F

я использовал метод sieve для вычисления списка простых чисел (в вычислении списка простых чисел возможно множество оптимизаций) Мы могли бы использовать этот факт .. не будет простого p такого, что F%p == 0 и R%p == 0 . так как gcd (F, R)=1