用于任意精度算术的GCD算法

时间:2013-02-23 19:11:47

标签: c algorithm gmp arbitrary-precision greatest-common-divisor

我完全坚持这个问题,所以我正在寻求任何帮助。

我认为每个人都知道基本的GCD计算算法,如二进制或欧几里德GCD。实现这种方法来计算两个单精度数不是问题。实际上,这只是几招。

我需要为多精度数字(超过10 ^ 5位)实现此方法(在C语言中)。有几个GNU库可用(GNU MP,MPFR,MPIR),它们有定义多精度数字并对它们进行操作的方法。它看起来像一个多精度数字存储在内存中,作为一对单精度部分又名“肢体”。

实现了一些用于查找gcd(a,b)的方法,但实际上它们很难满足我的需求。用于GCD计算的二进制方法仅在a和b恰好包含两个肢体时使用。当min(a,b)包含多于(即630)肢体等时使用的HGCD方法。 我发现很难弄清楚,如何使用任何长度的a和b来扩展这些方法中的任何一种。我还发现不同版本的GNU库包含不同的GCD算法版本和方法。

问题:我想知道是否有可能使二进制GCD算法在“肢体”方面使用任意长度的多精度整数,如果可能的话 - 得到任何帮助或想法如何在C中实现它。有没有人有任何想法或代码部分如何实现它?

我想考虑任何建议或任何其他解决方案来解决这个问题。

如果有人看一下,这是GNU MP二进制GCD方法的一部分(a = b = 2个肢体):

/* Use binary algorithm to compute G <-- GCD (U, V) for usize, vsize == 2.
   Both U and V must be odd. */
static inline mp_size_t
gcd_2 (mp_ptr gp, mp_srcptr up, mp_srcptr vp)
{
  printf("gcd_2 invoked\n");
  mp_limb_t u0, u1, v0, v1;
  mp_size_t gn;

  u0 = up[0];
  u1 = up[1];
  v0 = vp[0];
  v1 = vp[1];

  ASSERT (u0 & 1);
  ASSERT (v0 & 1);

  /* Check for u0 != v0 needed to ensure that argument to
   * count_trailing_zeros is non-zero. */
  while (u1 != v1 && u0 != v0)
    {
      unsigned long int r;
      if (u1 > v1)
  {
    sub_ddmmss (u1, u0, u1, u0, v1, v0);
    count_trailing_zeros (r, u0);
    u0 = ((u1 << (GMP_NUMB_BITS - r)) & GMP_NUMB_MASK) | (u0 >> r);
    u1 >>= r;
  }
      else  /* u1 < v1.  */
  {
    sub_ddmmss (v1, v0, v1, v0, u1, u0);
    count_trailing_zeros (r, v0);
    v0 = ((v1 << (GMP_NUMB_BITS - r)) & GMP_NUMB_MASK) | (v0 >> r);
    v1 >>= r;
  }
    }

  gp[0] = u0, gp[1] = u1, gn = 1 + (u1 != 0);

  /* If U == V == GCD, done.  Otherwise, compute GCD (V, |U - V|).  */
  if (u1 == v1 && u0 == v0)
    return gn;

  v0 = (u0 == v0) ? ((u1 > v1) ? u1-v1 : v1-u1) : ((u0 > v0) ? u0-v0 : v0-u0);
  gp[0] = mpn_gcd_1 (gp, gn, v0);

  return 1;
}

CodePaste of the above

1 个答案:

答案 0 :(得分:3)

只针对此问题专门推出自己的代码,为什么不呢? (10^9)^2符合64位int,因此您可以使用 base - (10^9)位数,每个都保存在64位int中。要表示2^(10^5) - 位值2^(10^5) ~= 10^30103,即具有~30103十进制数字的值,您只需要30103/9 ~= 3350个整数,这是内存中~27 kB的数组,对于每个涉及的数字。

According to WP, for binary GCD algorithm您只需要minus/2,这可以通过将每个数字减半来实现,偶尔将5*10^8传送到较低位(94 / 2 = 47 = {4,5+2}) 。最终乘以 2 k 可以使用朴素算法完成,因为它只需要完成一次。

在基地打印 - 10将是微不足道的。如果您不打算打印最终结果,那么您将不需要最终的乘法(或者如果您将结果报告为2^k*x),那么您可以使用基础 - 10^18数字,将要使用的位数减半。

您只需要通常的C整数运算来处理数字。