Найти наибольший делитель 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