1

I have an integer n, and I want to obtain a number which raised to the power of itself equals n. How can I do that?

  • Can you share the code you have so far? – Neil Jan 17 '17 at 10:33
  • 2
    Your question contradicts itself. Suppose `x^x = n` and `y^n = n`. Which number do you want to find, given `n`? `x` or `y`? – alexeykuzmin0 Jan 17 '17 at 10:35
  • There are *always* rounding errors when working with floating point numbers – Rakete1111 Jan 17 '17 at 10:35
  • `std::pow(n, 1/n)` will most likely return 1 – phuclv Jan 17 '17 at 10:39
  • @LưuVĩnhPhúc Of course, `n` should be cast to some floating-point type before all calculations. – alexeykuzmin0 Jan 17 '17 at 10:40
  • 1
    As the answers below have pointed out, solving `x**x = n` is *not* the same as computing the n-th root of n. However, to answer the last part of you question: computing the n-th root via `pow` can easily suffer from large errors due to the error magnification property of exponentiation; I provided a worked example for cube root in [this answer](http://stackoverflow.com/questions/26951407/why-does-math-cbrt1728-produce-a-more-accurate-result-than-math-pow1728-1-3/26958154#26958154) – njuffa Jan 17 '17 at 20:17

3 Answers3

5

So we want to solve the equation x^x = n. This is a quite different thing from finding y = n-th root of n in equivalent to y^n = n.

The first thing to do when looking at powers is to consider logs now using natural logs, x ln x = ln n. This does not help us too much and it's not a standard function, so some form of convergence routine will be needed and we want to solve f(x) = x ln x - ln n = 0. This function is nicely monotonic increasing a little faster than just x so it should be easy to solve.

We can use use Newton's method. First find the derivative f'(x) = log x + 1. Starting with a guess x1 an updated guess will be x2 = x1 - f(x1) / f'(x). If you do this a few times it should converge nicely. In my experiment to find x such that x^x = 21 it took just under 6 itterations to converge.

In psudocode

x[0] = ln(n);
for(i=0; i<6;++i ) {
    fx = x[i] * ln( x[i] ) - ln(n); 
    df = ln( x[i] ) + 1;
    x[i+1] = x[i] - fx / df;
}
println(x[6], pow(x[6], x[6]))
Salix alba
  • 7,536
  • 2
  • 32
  • 38
  • 1
    As `u=log(x)` solves `u*exp(u)=c=log(n)`, this can be solved using the LambertW function and its approximations. Using the approximation for large arguments `u=log(c)-log(log(c))` gives the initial value `x[0]=c/log(c)=log(n)/log(log(n))` from which Newton converges in very few steps. (In general you are doing something wrong if the scalar Newton method needs more than 15 steps. Usually it should be 3-6 steps to the basin of quadratic convergence, and then 3-4 steps to exhaust the double precision.) – Lutz Lehmann Jan 17 '17 at 11:53
  • 1
    @LutzL Found my problem, it was not the starting point, I was using log base 10 rather than natural logs. This meant I got the derivative wrong. With natural logs I'm getting much faster convergence, 5 steps does it. – Salix alba Jan 17 '17 at 13:57
4

You question states two things.

I want to get the nth root of n

This means finding the solution to x^n=n. For this std::pow(n, 1./n) would be a good thing. Note that 1/n will likely perform integer division if n is an integer, so you may well end up with std::pow(n, 0) which is 1.

I want to obtain a number which raised to the power of itself equals n

This is something completely different. You are trying to solve x^x=n for x. Taking the specific case of n=2 and asking Wolfram Alpha about it, it returns

x = exp(W(log(2)))

where W would be the Lambert W function. As far as I know this is not part of the C++ standard, so you'll likely have to find a library (in source code or dynamically linked) to compute that function for you. GSL might serve. Generalizing to different values of n should be obvious, though.

MvG
  • 57,380
  • 22
  • 148
  • 276
  • Set `x=exp(u)`, then `log(n)=x*log(x)=u*exp(u)` which is the inverse of LambertW so that `u=W(log(n))` and `x=exp(W(log(n)))`. No need for Wolfram Alpha except for inspiration. – Lutz Lehmann Jan 17 '17 at 11:59
  • @LutzL: Sure, I meant it as inspiration, and I used it as such myself since I hadn't had dealings with this function before. But even if I did, I want to educate others on how to come up with such keywords by themselves. – MvG Jan 17 '17 at 12:25
1

TL;DR: use std::pow.

You want to find 1/nth power of n. There's a standard function which finds yth power of x, called std::pow. It's always a good idea to use a standard function unless you have a strong reason to not.

So, it's better to rephrase this question to "do you have any reasons to not use std::pow?", and, since you're asking community, looks like you don't.

alexeykuzmin0
  • 6,344
  • 2
  • 28
  • 51