I am looking for an efficient algorithm to find nth root of a number. The answer must be an integer. I have found that newtons method and bisection method are popular methods. Are there any efficient and simple methods for integer output?
- with integer means no decimal places?Ishmeet– Ishmeet2013-12-22 13:42:42 +00:00Commented Dec 22, 2013 at 13:42
- @Ishmeet Yes Answer should be integeruser567879– user5678792013-12-22 13:46:58 +00:00Commented Dec 22, 2013 at 13:46
- So, do you want the result rounded, and if so, then how? Or do you want to get answer only if it is integer, and error (or whatever) otherwise?hyde– hyde2013-12-22 13:47:39 +00:00Commented Dec 22, 2013 at 13:47
- @hyde Result must be roundeduser567879– user5678792013-12-22 13:50:44 +00:00Commented Dec 22, 2013 at 13:50
- Why close this question!user567879– user5678792013-12-24 02:09:22 +00:00Commented Dec 24, 2013 at 2:09
5 Answers
#include <math.h> inline int root(int input, int n) { return round(pow(input, 1./n)); } This works for pretty much the whole integer range (as IEEE754 8-byte doubles can represent the whole 32-bit int range exactly, which are the representations and sizes that are used on pretty much every system). And I doubt any integer based algorithm is faster on non-ancient hardware. Including ARM. Embedded controllers (the microwave washing machine kind) might not have floating point hardware though. But that part of the question was underspecified.
13 Comments
1/n is an integer division, whereas in 1./n 1. is a double literal, so n gets converted to a double, and then divides 1.1.0 / n. It'll save a lot of people who might read the code a few "brain cycles" when they think what does this mean...-O2 or -O3? It seems obvious that if you compile without optimisations enabled then optimisations will not be performed.I know this thread is probably dead, but I don't see any answers I like and that bugs me...
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; } This method will also work with arbitrary precision fixed point math in case you want to compute something like sqrt(2) to 100 decimal places...
2 Comments
I question your use of "algorithm" when speaking of C programs. Programs and algorithms are not the same (an algorithm is mathematical; a C program is expected to be implementing some algorithm).
But on current processors (like in recent x86-64 laptops or desktops) the FPU is doing fairly well. I guess (but did not benchmark) that a fast way of computing the n-th root could be,
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); } } (I made a switch because many processors have hardware to compute sqrt and some have hardware to compute cbrt ..., so you should prefer these when relevant...).
I am not sure that n-th root of a negative number makes sense in general. So my root function takes some unsigned x and returns some unsigned number.
3 Comments
cbrt(-8)...pow here is specious and is guaranteed to give you wrong results on occasion, due to floating-point rounding error. For example, (unsigned)pow(4096, 1.0/6) is 3, but the 6th root of 4096 is actually 4. This is because pow returns 3.9999999999999996 instead of 4.0, which is because 1.0/6 is 0.1666666666666667 instead of exactly 1/6.Here is an efficient general implementation in C, using a simplified version of the "shifting nth root algorithm" to compute the floor of the nth root of x:
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; } It needs this function to compute the nth power of x (using the method of exponentiation by squaring):
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; } and this function to compute the floor of base-2 logarithm of x:
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 } Note: This assumes that your compiler understands GCC's __has_builtin test and that your compiler's uint64_t type is the same size as an unsigned long long.
Comments
You can try this C function to get the nth_root of an unsigned integer :
unsigned initial_guess_nth_root(unsigned n, unsigned nth){ unsigned res = 1; for(; n >>= 1; ++res); return nth ? 1 << (res + nth - 1) / nth : 0 ; } // return a number that, when multiplied by itself nth times, makes N. unsigned nth_root(const unsigned n, const unsigned nth) { unsigned a = initial_guess_nth_root(n , nth), b, c, r = nth ? a + (n > 0) : n == 1 ; for (; a < r; b = a + (nth - 1) * r, a = b / nth) for (r = a, a = n, c = nth - 1; c && (a /= r); --c); return r; } Example of output :
24 == (int) pow(15625, 1.0/3) 25 == nth_root(15625, 3) 0 == nth_root(0, 0) 1 == nth_root(1, 0) 4 == nth_root(4096, 6) 13 == nth_root(18446744073709551614, 17) // 64-bit 20 digits 11 == nth_root(340282366920938463463374607431768211454, 37) // 128-bit 39 digits Here is the github source.