我正在寻找一种有效的算法来查找数字的第n个根。答案必须是整数。我发现牛顿法和二分法是流行的方法。是否有任何有效且简单的整数输出方法?
答案 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
可以扩展相同的算法来计算代数方程的根。