查找数字的第n个根的算法

时间:2013-12-22 13:40:17

标签: c algorithm math

我正在寻找一种有效的算法来查找数字的第n个根。答案必须是整数。我发现牛顿法和二分法是流行的方法。是否有任何有效且简单的整数输出方法?

5 个答案:

答案 0 :(得分:17)

#include <math.h>
inline int root(int input, int n)
{
  return round(pow(input, 1./n));
}

这几乎适用于整个整数范围(因为IEEE754 8字节double可以完全代表整个32位int范围,它们是漂亮的表示和大小很多每个系统)。我怀疑任何基于整数的算法在非古代硬件上都更快。包括ARM。嵌入式控制器(微波洗衣机类)可能没有浮点硬件。但问题的这一部分是不明确的。

答案 1 :(得分:11)

我知道这个帖子可能已经死了,但我没有看到任何我喜欢的答案,这让我感到烦恼......

int root(int a, int n) {
    int v = 1, bit, tp, t;
    if (n == 0) return 0; //error: zeroth root is indeterminate!
    if (n == 1) return a;
    tp = iPow(v,n);
    while (tp < a) {    // first power of two such that v**n >= a
        v <<= 1;
        tp = iPow(v,n);
    }
    if (tp == a) return v;  // answer is a power of two
    v >>= 1;
    bit = v >> 1;
    tp = iPow(v, n);    // v is highest power of two such that v**n < a
    while (a > tp) {
        v += bit;       // add bit to value
        t = iPow(v, n);
        if (t > a) v -= bit;    // did we add too much?
        else tp = t;
        if ( (bit >>= 1) == 0) break;
    }
    return v;   // closest integer such that v**n <= a
}
// used by root function...
int iPow(int a, int e) {
    int r = 1;
    if (e == 0) return r;
    while (e != 0) {
        if ((e & 1) == 1) r *= a;
        e >>= 1;
        a *= a;
    }
    return r;
}

如果你想计算像sqrt(2)到100个小数位的东西,这个方法也适用于任意精度定点数学......

答案 2 :(得分:5)

在谈到algorithm时,我质疑您对“C programs”的使用。程序和算法不一样(算法是数学的; C程序应该实现某种算法)。

但是在目前的处理器上(比如最近的x86-64笔记本电脑或台式机),FPU表现相当不错。我猜(但没有基准测试)计算第n个根的快速方法可能是,

 inline unsigned root(unsigned x, unsigned n) {
   switch (n) {
     case 0: return 1;
     case 1: return x;
     case 2: return (unsigned)sqrt((double)x);
     case 3: return (unsigned)cbrt((double)x);
     default: return (unsigned) pow (x, 1.0/n);
   }
 }

(我做了一个转换,因为许多处理器都有硬件来计算sqrt,有些处理器有硬件要计算cbrt ...,所以在相关时你应该更喜欢这些......)。

我不确定负数的第n个根通常是否有意义。因此,我的root函数需要一些unsigned x并返回一些unsigned个数字。

答案 3 :(得分:0)

这是用C语言进行的有效通用实现,它使用简化版的“移位第n个根算法”来计算 x 的第 n 个根的底限:

uint64_t iroot(const uint64_t x, const unsigned n)
{
  if ((x == 0) || (n == 0)) return 0;
  if (n == 1) return x;

  uint64_t r = 1;
  for (int s = ((ilog2(x) / n) * n) - n; s >= 0; s -= n)
  {
    r <<= 1;
    r |= (ipow(r|1, n) <= (x >> s));
  }

  return r;
}

需要此函数来计算 x n 次幂(使用平方求幂的方法):

uint64_t ipow(uint64_t x, unsigned n)
{
  if (x <= 1) return x;

  uint64_t y = 1;
  for (; n != 0; n >>= 1, x *= x)
    if (n & 1)
      y *= x;
  return y;
}

以及用于计算 x 的以2为底的对数的下限的函数:

int ilog2(uint64_t x)
{
  #if __has_builtin(__builtin_clzll)
    return 63 - ((x != 0) * (int)__builtin_clzll(x)) - ((x == 0) * 64);
  #else
    int y = -(x == 0);
    for (unsigned k = 64 / 2; k != 0; k /= 2)
      if ((x >> k) != 0)
        { x >>= k; y += k; }
    return y;
  #endif
}

注意:这是假设您的编译器理解GCC的__has_builtin测试,并且您的编译器的uint64_t类型与unsigned long long的大小相同。

答案 4 :(得分:-3)

使用vedic数学获得最快的第n个根算法 请参阅http://www.slideshare.net/jadhavvitthal1989/vjs-root-algorithm-final

可以扩展相同的算法来计算代数方程的根。