【问题标题】:Pollard Rho factorization method implementation in CPollard Rho 分解方法在 C 中的实现
【发布时间】:2012-06-02 12:33:26
【问题描述】:

谁能帮我完成 pollard rho 的实现?我已经在 C 中实现了这一点。它适用于最多 10 位的数字,但它无法处理更大的数字。

请帮助我改进它以执行高达 18 位的数字分解。我的代码是this:

#include<stdio.h>
#include<math.h>
int gcd(int a, int b)
{
    if(b==0) return a ;
    else
    return(gcd(b,a%b)) ;
}

long long int mod(long long int a , long long int b , long long int n )
{    
     long long int x=1 , y=a ;
     while(b>0)
     {
        if(b%2==1)  x = ((x%n)*(y%n))%n ;
        y = ((y%n)*(y%n))%n ;
         b/=2 ;
     }
     return x%n ;
}

int isprimes(long long int u)
{  
    if(u==3)
    return 1 ;
     int a = 2 , i ;
     long long int k , t = 0 , r , p ;
     k = u-1 ;
     while(k%2==0)
     { k/=2 ; t++ ; }

         while(a<=3)                                                              /*der are no strong pseudoprimes common in base 2 and base 3*/
         {   
         r = mod(a,k,u) ;
             for(i = 1 ; i<=t ; i++)
             {
                  p = ((r%u)*(r%u))%u ;
                  if((p==1)&&(r!=1)&&(r!=(u-1)))
                  {  return 0 ; }
                  r = p ;
             }
          if(p!=1)
          return 0 ;
         else
          a++ ;
         } 

          if(a==4)
          return 1 ;

}

long long int pol(long long int u)
{ 
  long long int x = 2 , k , i , a , y , c , s;
  int d = 1 ;
   k = 2 ;
   i = 1 ;
   y = x ;
   a = u ;
   if(isprimes(u)==1)
   { 
     return 1;
   }
   c=-1 ;
   s = 2 ;
   while(1)
   {
     i++;
     x=((x%u)*(x%u)-1)% u ;

     d = gcd(abs(y-x),u) ;

     if(d!=1&&d!=u)
     { printf("%d ",d);
       while(a%d==0) { a=a/d;  }

        x = 2 ;
        k = 2 ;
        i = 1 ;
        y = x ;
        if(a==1)
        { return 0 ; }
        if(isprimes(a)!=0)
        { return a ; }
        u=a ;

     }
     if(i==k)
     {y = x ; k*=2 ; c = x ;}                                                       /*floyd cycle detection*/
        if(c==x)                                                                 
     { x = ++s ; }
    }
    return ;

}

int main()
{
   long long int t ;
    long long int i , n , j , k , a , b  , u ;
    while(scanf("%lld",&n)&&n!=0)
    { u = n ; k = 0 ;
    while(u%2==0)
       {  u/=2 ; k = 1 ; }
      if(k==1) printf("2 ") ;
      if(u!=1)
      t = pol(u) ;
        if(u!=1) 
      {
           if(t==1)
           { printf("%lld",u) ; }
           else
           if(t!=0)
           { printf("%lld",t) ; }
      }
          printf("\n");
    }
    return 0;
}

对不起,长代码.....我是一个新的编码员。

【问题讨论】:

  • 建议你写一些单元测试...
  • 你试过缓存素数吗?
  • 这段代码让我感到恶心......我知道这是一种竞争性的编码风格,但请您在提问之前重写一下吗?
  • 对不起! ....我刚刚注意到函数 (x^2-1)%u 中 x 的值溢出了...你能建议一种措施来避免这种溢出吗? @EmilVikström 不,内存限制不允许我这样做....不是这些大数字。
  • 我只是想知道如何为大数实现 Pollard rho 分解,直到具有 18 位数字的数字?

标签: c algorithm factorization


【解决方案1】:

当您将两个数字相乘以 m 为模时,中间乘积可以接近 m^2。所以如果你使用64位无符号整数类型,它可以处理的最大模数是2^32,如果模数更大,可能会发生溢出。模数稍微大一点的情况是很少见的,但这只会让它不那么明显,如果模数允许溢出的可能性,你不能指望幸运。

如果您选择绝对值最多为 m/2 的残差类模 m 或等效值的代表,则可以将范围扩大两倍:

uint64_t mod_mul(uint64_t x, uint64_t y, uint64_t m)
{
    int neg = 0;
    // if x is too large, choose m-x and note that we need one negation for that at the end
    if (x > m/2) {
        x = m - x;
        neg = !neg;
    }
    // if y is too large, choose m-y and note that we need one negation for that at the end
    if (y > m/2) {
        y = m - y;
        neg = !neg;
    }
    uint64_t prod = (x * y) % m;
    // if we had negated _one_ factor, and the product isn't 0 (mod m), negate
    if (neg && prod) {
        prod = m - prod;
    }
    return prod;
}

因此,这将允许使用 64 位无符号类型的高达 2^33 的模数。不是很大的一步。

该问题的推荐解决方案是使用大整数库,例如 GMP 在大多数(如果不是全部)Linux 发行版上都可作为分发包使用,并且(相对)可轻松安装在 Windows 上。

如果这不是一个选项(真的,你确定吗?),您可以使用俄罗斯农民乘法使其适用于更大的模数(对于无符号 64 位整数类型,最高可达 2^63):

x * y = 2 * (x * (y/2)) + (x * (y % 2))

所以对于计算,你只需要2*(m-1) 不会溢出。

uint64_t mod_mult(uint64_t x, uint64_t y, uint64_t m)
{
    if (y == 0) return 0;
    if (y == 1) return x % m;
    uint64_t temp = mod_mult(x,y/2,m);
    temp = (2*temp) % m;
    if (y % 2 == 1) {
        temp = (temp + x) % m;
    }
    return temp;
}

但请注意,此算法需要 O(log y) 步,因此在实践中相当慢。对于较小的m,您可以加快速度,如果2^k*(m-1) 没有溢出,您可以按k 位而不是单个位(x*y = ((x * (y &gt;&gt; k)) &lt;&lt; k) + (x * (y &amp; ((1 &lt;&lt; k)-1))))的步骤进行,如果您的模数永远不会,这是一个很好的改进比如大于 48 或 56 位。

使用模乘的变体,您的算法将适用于更大的数字(但它会明显变慢)。您也可以尝试测试模数的大小和/或因素以确定使用哪种方法,如果是m &lt; 2^32 或x &lt; (2^64-1)/y,简单的(x * y) % m 就可以了。

【讨论】:

  • 谢谢...帮助很大:)
猜你喜欢
  • 1970-01-01
  • 2014-11-12
  • 1970-01-01
  • 2011-11-24
  • 1970-01-01
  • 1970-01-01
  • 2011-08-27
  • 1970-01-01
  • 2014-09-07
相关资源
最近更新 更多