Задать вопрос
@Idwln

Более быстрый способ нахождения всех делителей числа?

Хочу узнать, какой наиболее быстрый способ нахождения всех делителей числа есть?( в среднем случае )
Пользовался всегда данным(указанным ниже) куском кода, но решал простые задачи. Когда дело пришло к большим цифрам, понял, что он не самый эффективный.
Код:
import collections
import itertools


def get_prime_divisors(n):
    i = 2
    while i * i <= n:
        if n % i == 0:
            n /= i
            yield i
        else:
            i += 1

    if n > 1:
        yield n


def calc_product(iterable):
    acc = 1
    for i in iterable:
        acc *= i
    return acc


def get_all_divisors(n):
    primes = get_prime_divisors(n)

    primes_counted = collections.Counter(primes)

    divisors_exponentiated = [
        [div ** i for i in range(count + 1)]
        for div, count in primes_counted.items()
    ]

    for prime_exp_combination in itertools.product(*divisors_exponentiated):
        yield calc_product(prime_exp_combination)

P.s: Сам код взял из интернета, ибо в первый раз не было времени придумывать свой велосипед.
  • Вопрос задан
  • 2485 просмотров
Подписаться 2 Простой 4 комментария
Пригласить эксперта
Ответы на вопрос 4
mayton2019
@mayton2019
Bigdata Engineer
Суть вопроса - алгоритм факторизации.

Чтобы ускорить факторизацию есть много путей. Во первых - отказаться от языка Python в пользу C++ или Rust.

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

И step надо делать не по 1 элементу а по нечётным начиная с 3.

Есть ещё алгоритм Эратосфена. Обрати внимание.

И есть очень глобальная задача, такая как доказательство простоты. Для нее есть целый список алгоритмов. Они сложные и интересные. Часть из них - вероятностные. Используются в критпографии.
Ответ написан
Комментировать
wataru
@wataru Куратор тега Алгоритмы
Разработчик на С++, экс-олимпиадник.
Это самый быстрый способ факторизации одного числа. Если не хватает, то может в задаче можно факторизовать все числа сразу. Каким нибудь решетом можно найти минимальный делитель для всех чисел до n за O(n). Дальше каждое число раскладывается на множители моментально.
Ответ написан
sheerluck
@sheerluck
Я нахожу все делители числа в SageMath (https://www.sagemath.org):
sage: 256893450689.divisors()
[1, 19, 13520707931, 256893450689]
sage: 252323674611367475532285533.divisors()
[1, 110933, 2267937467, 1002919711403, 251589107026711, 111256892345068999, 2274559189883690836201, 252323674611367475532285533]
Ответ написан
Комментировать
@ArseniyRybasov
Есть 2 приходящих на ум быстрых способов поиска делителей числа. Это поиск до корня числа и разложение числа на простые множители и перебор всех их комбинаций.
Первый способ программа на Python ищет делители числа 72576 * 10 ^ 12 (2600 делителей) за 22,742 секунды. Второй кажется быстрее, но из-за самого принципа поиска код получается длинным и сложным и программа будет искать делители вечность xD

Но самый быстрый способ - это тот, который я придумал). Он выполняется так:
1. Раскладывает число на простые множители
2. Идёт по списку простых множителей (i) и списку всех известных делителей числа (j):
2.1. Если (простой множитель с индексом i) * (известный делитель с индексом j) не встречается в списке известных делителей числа, то в список это значение не добавляется (чтобы каждый раз цикл не проходился по повторяющимся значениям)
2.2. Если простой множитель с индексом i отсутствует, то он добавляется
3. Добавляет в конце списка делителей числа единицу
4. Возвращает отсортированный список

Моя реализация:
def divisors(n):
    divs = []
    prdivs = []
    nownum = n
    isPrime = False

    while isPrime == False:
        isPrime = True
        for i in range(2, int(nownum ** 0.5) + 1):
            if nownum % i == 0:
                prdivs.append(i)
                isPrime = False
                nownum //= i
                break

    prdivs.append(nownum)

    for i in range(len(prdivs)):
        for j in range(len(divs)):
            if divs[j] * prdivs[i] not in divs:
                divs.append(divs[j] * prdivs[i])

        if prdivs[i] not in divs:
            divs.append(prdivs[i])

    divs.append(1)
    return sorted(divs)

Он ищет делители числа 72576 * 10 ^ 12 за 0,055 секунд, а у числа 72576 * 10 ^ 50 (29580 делителей) за 17,489 секунд!
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы