给定一个正整数n ,并且它是复合的,找到它的除数。
例子:
Input: n = 12;
Output: 2 [OR 3 OR 4]
Input: n = 187;
Output: 11 [OR 17]
暴力破解方法:测试所有小于n的整数,直到找到除数。
即兴:测试所有小于√n的整数
足够多的数量仍然意味着大量工作。 Pollard的Rho是素数分解算法,对于具有较小素数的大量复合数尤其快速。 Rho算法最显着的成功是第八个费马数的因式分解:1238926361552897 * 9346163971535797776916355819960689658405123754163818858020321。
Rho算法是一个不错的选择,因为第一个素数要比另一个小得多。
Pollard的Rho算法中使用的概念:
- 如果两个数字x和y相等,则称n为模(x = y模n),如果
- 它们的绝对差是n,OR的整数倍
- 当除以n时,它们每个都留下相同的余数。
- 最大公因数是最大的数,该数被均分为每个原始数。
- 生日悖论:即使对于一小群人,两个人拥有相同生日的概率也异常高。
- 弗洛伊德(Floyd)的循环查找算法:如果乌龟和野兔从同一点开始并以一个周期运动,以致野兔速度是乌龟速度的两倍,则它们必须在某个点相遇。
算法:
- 从随机的x和c开始。取y等于x且f(x)= x 2 + c。
- 虽然没有获得除数
- 将x更新为f(x)(模n)[乌龟移动]
- 将y更新为f(f(y))(模n)[野兔移动]
- 计算| xy |的GCD和n
- 如果GCD不统一
- 如果GCD为n,则从步骤2开始重复另一组x,y和c
- 其他GCD是我们的答案
插图:
让我们假设n = 187,并针对不同的随机值考虑不同的情况。
- 一个使算法找到结果的随机值示例:
y = x = 2且c = 1,因此,我们的f(x)= x 2 + 1。
- 随机值的示例,以使算法更快地找到结果:
y = x = 110且’c’=183。因此,我们的f(x)= x 2 + 183。
- 使得算法找不到结果的随机值示例:
x = y = 147,c =67。因此,我们的f(x)= x 2 + 67。
下面是上述算法的C / C++实现:
C++
/* C++ program to find a prime factor of composite using
Pollard's Rho algorithm */
#include
using namespace std;
/* Function to calculate (base^exponent)%modulus */
long long int modular_pow(long long int base, int exponent,
long long int modulus)
{
/* initialize result */
long long int result = 1;
while (exponent > 0)
{
/* if y is odd, multiply base with result */
if (exponent & 1)
result = (result * base) % modulus;
/* exponent = exponent/2 */
exponent = exponent >> 1;
/* base = base * base */
base = (base * base) % modulus;
}
return result;
}
/* method to return prime divisor for n */
long long int PollardRho(long long int n)
{
/* initialize random seed */
srand (time(NULL));
/* no prime divisor for 1 */
if (n==1) return n;
/* even number means one of the divisors is 2 */
if (n % 2 == 0) return 2;
/* we will pick from the range [2, N) */
long long int x = (rand()%(n-2))+2;
long long int y = x;
/* the constant in f(x).
* Algorithm can be re-run with a different c
* if it throws failure for a composite. */
long long int c = (rand()%(n-1))+1;
/* Initialize candidate divisor (or result) */
long long int d = 1;
/* until the prime factor isn't obtained.
If n is prime, return n */
while (d==1)
{
/* Tortoise Move: x(i+1) = f(x(i)) */
x = (modular_pow(x, 2, n) + c + n)%n;
/* Hare Move: y(i+1) = f(f(y(i))) */
y = (modular_pow(y, 2, n) + c + n)%n;
y = (modular_pow(y, 2, n) + c + n)%n;
/* check gcd of |x-y| and n */
d = __gcd(abs(x-y), n);
/* retry if the algorithm fails to find prime factor
* with chosen x and c */
if (d==n) return PollardRho(n);
}
return d;
}
/* driver function */
int main()
{
long long int n = 10967535067;
printf("One of the divisors for %lld is %lld.",
n, PollardRho(n));
return 0;
}
Java
/* Java program to find a prime factor of composite using
Pollard's Rho algorithm */
import java.util.*;
class GFG{
/* Function to calculate (base^exponent)%modulus */
static long modular_pow(long base, int exponent,
long modulus)
{
/* initialize result */
long result = 1;
while (exponent > 0)
{
/* if y is odd, multiply base with result */
if (exponent % 2 == 1)
result = (result * base) % modulus;
/* exponent = exponent/2 */
exponent = exponent >> 1;
/* base = base * base */
base = (base * base) % modulus;
}
return result;
}
/* method to return prime divisor for n */
static long PollardRho(long n)
{
/* initialize random seed */
Random rand = new Random();
/* no prime divisor for 1 */
if (n == 1) return n;
/* even number means one of the divisors is 2 */
if (n % 2 == 0) return 2;
/* we will pick from the range [2, N) */
long x = (long)(rand.nextLong() % (n - 2)) + 2;
long y = x;
/* the constant in f(x).
* Algorithm can be re-run with a different c
* if it throws failure for a composite. */
long c = (long)(rand.nextLong()) % (n - 1) + 1;
/* Initialize candidate divisor (or result) */
long d = 1L;
/* until the prime factor isn't obtained.
If n is prime, return n */
while (d == 1)
{
/* Tortoise Move: x(i+1) = f(x(i)) */
x = (modular_pow(x, 2, n) + c + n) % n;
/* Hare Move: y(i+1) = f(f(y(i))) */
y = (modular_pow(y, 2, n) + c + n) % n;
y = (modular_pow(y, 2, n) + c + n) % n;
/* check gcd of |x-y| and n */
d = __gcd(Math.abs(x - y), n);
/* retry if the algorithm fails to find prime factor
* with chosen x and c */
if (d == n) return PollardRho(n);
}
return d;
}
// Recursive function to return gcd of a and b
static long __gcd(long a, long b)
{
return b == 0? a:__gcd(b, a % b);
}
/* driver function */
public static void main(String[] args)
{
long n = 10967535067L;
System.out.printf("One of the divisors for " + n + " is " +
PollardRho(n));
}
}
// This code contributed by aashish1995
Python3
# Python 3 program to find a prime factor of composite using
# Pollard's Rho algorithm
import random
import math
# Function to calculate (base^exponent)%modulus
def modular_pow(base, exponent,modulus):
# initialize result
result = 1
while (exponent > 0):
# if y is odd, multiply base with result
if (exponent & 1):
result = (result * base) % modulus
# exponent = exponent/2
exponent = exponent >> 1
# base = base * base
base = (base * base) % modulus
return result
# method to return prime divisor for n
def PollardRho( n):
# no prime divisor for 1
if (n == 1):
return n
# even number means one of the divisors is 2
if (n % 2 == 0):
return 2
# we will pick from the range [2, N)
x = (random.randint(0, 2) % (n - 2))
y = x
# the constant in f(x).
# Algorithm can be re-run with a different c
# if it throws failure for a composite.
c = (random.randint(0, 1) % (n - 1))
# Initialize candidate divisor (or result)
d = 1
# until the prime factor isn't obtained.
# If n is prime, return n
while (d == 1):
# Tortoise Move: x(i+1) = f(x(i))
x = (modular_pow(x, 2, n) + c + n)%n
# Hare Move: y(i+1) = f(f(y(i)))
y = (modular_pow(y, 2, n) + c + n)%n
y = (modular_pow(y, 2, n) + c + n)%n
# check gcd of |x-y| and n
d = math.gcd(abs(x - y), n)
# retry if the algorithm fails to find prime factor
# with chosen x and c
if (d == n):
return PollardRho(n)
return d
# Driver function
if __name__ == "__main__":
n = 10967535067
print("One of the divisors for", n , "is ",PollardRho(n))
# This code is contributed by chitranayal
C#
/* C# program to find a prime factor of composite using
Pollard's Rho algorithm */
using System;
class GFG
{
/* Function to calculate (base^exponent)%modulus */
static long modular_pow(long _base, int exponent,
long modulus)
{
/* initialize result */
long result = 1;
while (exponent > 0)
{
/* if y is odd, multiply base with result */
if (exponent % 2 == 1)
result = (result * _base) % modulus;
/* exponent = exponent/2 */
exponent = exponent >> 1;
/* base = base * base */
_base = (_base * _base) % modulus;
}
return result;
}
/* method to return prime divisor for n */
static long PollardRho(long n)
{
/* initialize random seed */
Random rand = new Random();
/* no prime divisor for 1 */
if (n == 1) return n;
/* even number means one of the divisors is 2 */
if (n % 2 == 0) return 2;
/* we will pick from the range [2, N) */
long x = (long)(rand.Next(0, -(int)n + 1));
long y = x;
/* the constant in f(x).
* Algorithm can be re-run with a different c
* if it throws failure for a composite. */
long c = (long)(rand.Next(1, -(int)n));
/* Initialize candidate divisor (or result) */
long d = 1L;
/* until the prime factor isn't obtained.
If n is prime, return n */
while (d == 1)
{
/* Tortoise Move: x(i+1) = f(x(i)) */
x = (modular_pow(x, 2, n) + c + n) % n;
/* Hare Move: y(i+1) = f(f(y(i))) */
y = (modular_pow(y, 2, n) + c + n) % n;
y = (modular_pow(y, 2, n) + c + n) % n;
/* check gcd of |x-y| and n */
d = __gcd(Math.Abs(x - y), n);
/* retry if the algorithm fails to find prime factor
* with chosen x and c */
if (d == n) return PollardRho(n);
}
return d;
}
// Recursive function to return gcd of a and b
static long __gcd(long a, long b)
{
return b == 0 ? a:__gcd(b, a % b);
}
/* Driver code */
public static void Main(String[] args)
{
long n = 10967535067L;
Console.Write("One of the divisors for " + n + " is " +
PollardRho(n));
}
}
// This code is contributed by aashish1995
Javascript
输出:
One of the divisors for 10967535067 is 104729
这是如何运作的?
令n为复合数(非素数) 。由于n是复合的,因此它具有非平凡的因子f
现在假设我们必须从[0,n-1]范围中选择两个数字x和y。我们唯一获得x = y模n的时间是x和y相同时。但是,由于f <√n,即使x和y不相同(生日悖论),也有很好的机会以x = y为模f。
我们首先从集合{0,1,…,n-1}中随机选择x进行替换,以形成序列s 1 ,s 2 ,s 3 。 i = s i mod f ,我们的序列现在每个&sacute;我属于{0,1,…,f-1}。因为这两个集合都是有限的,所以最终两个集合中都会有一个重复的整数。我们希望在&sacute;中早日实现重复。 i ,因为f
Rho算法的核心是获取随机值并评估GCD。为了减少昂贵的GCD计算,我们可以使用弗洛伊德(Floyd)的周期检测来实现Pollard的Rho(这可以通过乌龟比喻来理解,其中乌龟一次一次穿过每个元素,而兔子在同一点开始但移动速度是乌龟的两倍。我们将具有相同的多项式f(x),从随机x 0开始,y 0 = x 0 ,然后计算x i + 1 = f(x i )和y i + 1 = f(f(y i ) )。由于我们对d的了解不多,因此多项式的典型选择是f(x)= x 2 + c(取模n)(是的,“ c”也可以随机选择)。
笔记:
- 算法将对质数无限期运行。
- 该算法可能找不到因素并返回复合n的故障。在这种情况下,我们使用x,y和c的不同集合,然后重试。
- 上面的算法仅找到一个除数。为了找到一个素数,我们可以递归分解除数d,运行d和n / d的算法。周期长度通常约为√d。