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

use*_*879 10 c algorithm math

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

rub*_*nvb 18

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

这适用于几乎整个整数范围(因为IEEE754 8字节doubles可以int精确地表示整个32位范围,这是几乎每个系统上使用的表示和大小).我怀疑任何基于整数的算法在非古代硬件上都更快.包括ARM.嵌入式控制器(微波洗衣机类)可能没有浮点硬件.但问题的这一部分未得到详细说明.

  • 我更喜欢写'1.0/n`.当他们想到这意味着什么时,它会拯救很多可能会在代码中读取一些"脑循环"的人. (9认同)
  • @MaduraAnushanga:为什么不编译`-O2`或`-O3`?很明显,如果在没有启用优化的情况下进行编译,则不会执行优化. (5认同)
  • s/you /编译器/ (2认同)
  • 在那里,我相信`inline`给出了最好的<purrformance>. (2认同)
  • 很棒的基准测试就在那里.正如Scooter曾经说过的那样:"从统计数据来看,这些是Pandora上最安全的车.让我向你扔一些数据......五个!二十三个!八百六十个!" (2认同)

小智 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;
}
Run Code Online (Sandbox Code Playgroud)

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


Bas*_*tch 5

在谈到C程序时,我质疑你对" 算法 "的使用.程序和算法不一样(算法是数学的; 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);
   }
 }
Run Code Online (Sandbox Code Playgroud)

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

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

  • 我[问题](http://en.wikipedia.org/wiki/Question)在谈到任何程序时你的[质疑](http://en.wikipedia.org/wiki/Question)这个术语算法...... ? (2认同)
  • 在这里使用双精度浮点函数 `pow` 是似是而非的,并且由于浮点舍入误差,有时**保证会给你错误的结果**。例如,`(unsigned)pow(4096, 1.0/6)` 是`3`,但4096的第6个根实际上是4。这是因为`pow`返回的是`3.99999999999999996`而不是`4.0`,这是因为`1.0/6` 是 `0.1666666666666667` 而不是 1/6。 (2认同)