Нахождение целых степенных корней

Каков наилучший (наиболее эффективный) алгоритм нахождения всех целых степенных корней числа?

То есть, имея число n, я хочу найти b (основание) и e (показатель степени) такие, что

n = бе

Я хочу получить все возможные пары значений b и e

Ps: n b и e должны быть целыми положительными числами .


person Gautam    schedule 26.12.2011    source источник
comment
Должен ли e быть целым числом?   -  person Francois G    schedule 26.12.2011
comment
Извините, я забыл упомянуть об этом, я обновил вопрос   -  person Gautam    schedule 26.12.2011
comment
Я все еще ищу, чтобы найти что-то. делал это более 45 минут   -  person Gautam    schedule 26.12.2011
comment
Если ваша проблема заключается в простой факторизации, сначала найдите все простые числа меньше n/2 и создайте массив целых чисел размера n/2 + 1, назовите его A, установленным в ноль при запуске, затем для каждого из простых чисел (p) проверьте n/p == 0 или нет, пока n/p == 0, установите n/= p и увеличьте A[p], тогда у вас будет простая факторизация. Если вам нужен более быстрый метод для этого, задайте его в новом вопросе.   -  person Saeed Amiri    schedule 26.12.2011
comment
@SaeedAmiri: Спасибо, я тоже попробую.   -  person Gautam    schedule 26.12.2011
comment
@SaeedAmiri нет необходимости идти к n/2, просто иди к sqrt(n). Любой оставшийся множитель автоматически становится последним простым числом.   -  person btilly    schedule 26.12.2011
comment
@btilly да, вы правы, но все это можно сделать быстрее, это просто наивный алгоритм.   -  person Saeed Amiri    schedule 26.12.2011
comment
@Gautam K: Проблема, которую вы определили, на самом деле заключается в поиске всех целых корней степени, а не в возведении в степень. Возведение в степень находит Y=X**a для известных X и a.   -  person Serge Dundich    schedule 28.12.2011
comment
@SergeDundich: Пожалуйста, отредактируйте заголовок, спасибо, что указали на это.   -  person Gautam    schedule 28.12.2011


Ответы (4)


Я думаю, что подход грубой силы должен работать: попробуйте все e от 2 (1 - тривиальное решение) и выше, взяв r = n ^ 1/e, double. Если r меньше 2, остановитесь. В противном случае вычислите ceil(r)^e и floor(r)^e и сравните их с n (вам нужны ceil и floor для компенсации ошибок в представлениях с плавающей запятой). Предполагая, что ваши целые числа умещаются в 64 бита, вам не нужно будет пробовать более 64 значений e.

Вот пример на С++:

#include <iostream>
#include <string>
#include <sstream>
#include <math.h>
typedef long long i64;
using namespace std;
int main(int argc, const char* argv[]) {
    if (argc == 0) return 0;
    stringstream ss(argv[1]);
    i64 n;
    ss >> n;
    cout << n << ", " << 1 << endl;
    for (int e = 2 ; ; e++) {
        double r = pow(n, 1.0 / e);
        if (r < 1.9) break;
        i64 c = ceil(r);
        i64 f = floor(r);
        i64 p1 = 1, p2 = 1;
        for (int i = 0 ; i != e ; i++, p1 *= c, p2 *= f);
        if (p1 == n) {
            cout << c << ", " << e << endl;
        } else if (p2 == n) {
            cout << f << ", " << e << endl;
        }
    }
    return 0;
}

При вызове с 65536 он выдает следующий вывод:

65536, 1
256, 2
16, 4
4, 8
2, 16
person Sergey Kalinichenko    schedule 26.12.2011
comment
Кажется правдоподобным, не могли бы вы пояснить решение с помощью кода? - person Gautam; 26.12.2011
comment
@dasblinkenlight: это правильная идея для идеального решения. Вам нужно только попробовать e от 2 до log2(n) (логарифм по основанию 2). Единственное, код возведения в степень for (int i = 0 ; i != e ; i++, p1 *= c, p2 *= f); далек от оптимального (вы можете делать меньше 2*log2(e) умножений вместо e умножений). Но в любом случае основная идея верна. - person Serge Dundich; 29.12.2011
comment
@SergeDundich Я сохранил наивный код power(c,e), потому что e имеет низкую жесткую границу 64. Умный алгоритм power(c,e) создал бы больше вопросов (даже цикл for, который у меня есть сейчас, может выиграть от комментария; алгоритм мощности log2 был бы еще менее очевидным ), поэтому я сохранил тривиальный алгоритм. - person Sergey Kalinichenko; 29.12.2011

Сначала найдите простую факторизацию n: n = p1e1 p2e2 p3e3 ...

Затем найдите наибольший общий делитель g чисел e1, e2, e3, ..., используя алгоритм Евклида.

Теперь для любого фактора e из g вы можете использовать:

b = p1e1/e p2e2/e p3e3/e ...

И у вас есть n = be.

person interjay    schedule 26.12.2011
comment
На самом деле я пытался реализовать простой алгоритм факторизации, и мне нужно было решить эту проблему. По иронии судьбы вы просите меня найти основные факторы. - person Gautam; 26.12.2011
comment
@ChingPing: это очень далеко от отличного подхода. Поиск целых степенных корней — очень простая задача с полиномиальным временем, в то время как целочисленная факторизация — очень сложная задача, для которой неизвестен алгоритм с полиномиальным временем. - person Serge Dundich; 29.12.2011
comment
@SergeDundich Является ли полиномиальным, если n очень большое? в противном случае я не понимаю вашей точки зрения, поскольку поиск простых чисел для небольших чисел также является полиномиальным! и даже лучше, у нас есть алгоритмы, такие как rho pollard для больших чисел! ТАКЖЕ обратите внимание, что проблема заключается в поиске ВСЕХ целых корней степени - person FUD; 29.12.2011
comment
@ChingPing: полиномиально ли это, если n очень-очень велико? Конечно, это является. Говоря о полиномиальном (с входным размером P(s) = P(log2(n))) времени работы, мы говорим о времени работы t(s)=O(P(s)) для любого возможного n и, следовательно, для любого возможного s=log2(n), включая очень и очень большие. - person Serge Dundich; 29.12.2011
comment
@ChingPing: И для проблемы целочисленной факторизации не существует полиномиального алгоритма. Все известные алгоритмы, включая ро Полларда, квадратичное сито, сито общего числового поля (наиболее известный универсальный алгоритм), намного медленнее полиномиального. - person Serge Dundich; 29.12.2011
comment
@ChingPing: И, конечно же, я говорю о поиске ВСЕХ целых корней степени. - person Serge Dundich; 29.12.2011
comment
@SergeDundich, не могли бы вы рассказать нам решение? - person FUD; 29.12.2011
comment
@ChingPing: не могли бы вы рассказать нам решение? Решение чего? Нахождение ВСЕХ целых степенных корней? Я могу, но dasblinkenlight уже сделал это для интегрированных типов целых чисел (небольшие числа до 52 бит). Если у вас есть очень длинные n произвольной длины (скажем, 1 Гб или больше), то идея та же: вы пробуете все e от 2 до log2(n), затем находите e-степенной корень (самый большой x, что x**e <= n) и если это точный корень мощности (т.е. x**e == n) то вы нашли нетривиальное решение b = x, e то повторяете операцию с n = x или иначе переходите к e = e+1. - person Serge Dundich; 29.12.2011

Удовлетворит ли мой подход ваши потребности, зависит от размеров задачи.

Во-первых, есть одно очевидное решение: e = 1, верно? С этого момента, если вы хотите найти все решения: все алгоритмы, которые я могу придумать, требуют найти какой-то простой множитель n. Если это всего лишь одна независимая задача, ничего лучше, чем перебор простых чисел, нельзя сделать (если я не ошибаюсь). После того, как вы найдете первый простой множитель p и соответствующий ему показатель степени (то есть наибольшее число k, такое что p^k/n), вам нужно проверить на e только делители k. Для каждого такого показателя степени l (опять же l повторяет все делители k) вы можете использовать бинарный поиск, чтобы увидеть, является ли корень l-го числа n целым числом (эквивалентно поиску нового решения).

person Boris Strandjev    schedule 26.12.2011
comment
(если я не ошибаюсь) Вы не правы. Алгоритмы целочисленной факторизации намного быстрее, чем грубая сила простых чисел. И нахождение всех целых корней степени, которые задает исходный вопрос, является гораздо более простой (полиномиальное время) задачей. - person Serge Dundich; 28.12.2011
comment
Как некоторые люди могли бы сказать: «Единственное, что может быть лучше, чем быть правым, — это быть неправым». Спасибо, что обучили меня. PS: Только вскоре после того, как я написал, я понял, что решение, которое я предлагаю, является чем-то средним, и я с трудом мог придумать постановку задачи, для которой мое решение будет оптимальным (вероятно, факторизуя огромное число, для которого, как вы знаете, существует очень мало главный фактор?). - person Boris Strandjev; 28.12.2011

Смешайте подходы interjay и dasblinkenlight. Сначала найдите все малые простые множители (если они есть) и их показатели в простой факторизации n. Соответствующее значение "маленький" зависит от n, для среднего размера n может быть достаточно p <= 100, для большого более подходящим может быть n, p <= 10000 или p <= 10^6. Если вы найдете малые простые множители, вы знаете, что e должно делить наибольший общий делитель всех найденных вами показателей степени. Довольно часто gcd будет 1. В любом случае, диапазон возможных показателей будет уменьшен, если n не имеет малых простых делителей, вы знаете, что e <= log(n)/log(small_limit), что является хорошим сокращением от log(n)/log(2), если вы нашли пару маленьких простых множители, gcd их показателей g, а оставшийся сомножитель n равен m, вам нужно только проверить делители g, не превышающие log(m)/log(small_limit).

person Daniel Fischer    schedule 26.12.2011