0

I am calculating the n'th root of a positive integer using standard library method pow() .Here is the snippet from my program :

double x,y;
x=pow(64,(1.0/3));
int z;
printf("x=%lf\n",x);
z=(int)x;
printf("%d\n",z);

But while finding cube root of 64. X is printed as 4.000000 while z as 3. Why so ?

Can someone suggest a better algorithm , for the same ?

Namit Sinha
  • 1,345
  • 3
  • 14
  • 29
Dharmesh
  • 17
  • 1
  • 1
    Types are important, make sure you write `64.0` (double) instead of `64` (integer), same for `3`. Also, have you included math (I assume you have, but just checking). Does your compiler provide you any warnings? – ilent2 Jun 08 '14 at 10:54
  • For your particular issue, I suspect your output is being rounded up in printf but your cast is flooring. Try `int z = round(x);` instead. – ilent2 Jun 08 '14 at 10:56
  • 2
    Probably x is something like 3.99999999999737 or otherwise close to 4 and gets rounded by `printf` whilst casting to int just truncates it. – user1942027 Jun 08 '14 at 10:56
  • This is most probably due to floating point precision. – Abhishek Bansal Jun 08 '14 at 10:56
  • z=round(x) will give wrong answer for 4th root of 64 @ilent2 – Dharmesh Jun 08 '14 at 11:05

3 Answers3

2

If you print more digits on x, you'll see what the problem is (I chose 30 randomly):

double x ;
x = pow(64, 1.0/3);
printf("x=%.30lf\n",x);

Output:

x=3.99999999...999600000000 

So obvisouly, if you cast x into a int it will became 3.

There is not a 'perfect' solution. If you're only dealing with integer, you could create your own root function, but if you want to be able to use float, you'need to deal with accuracy problem due to floating point representation.

There are maybe some C libraries which could help you with this kind of problems.

Holt
  • 32,271
  • 6
  • 74
  • 116
  • Can you please tell the root function to find nth root of a integer @Holt – Dharmesh Jun 08 '14 at 11:12
  • @Dharmesh I don't know it, but you can find many post on SO like this one http://stackoverflow.com/questions/8826822/calculate-nth-root-with-integer-arithmetic or this one http://stackoverflow.com/questions/7407752/integer-nth-root. – Holt Jun 08 '14 at 11:27
2

The int override rounds down. Since floating point operations are inaccurate, the calculation may be 3.999999...

Use round(x) to get the correct result.

Since you always want to round down, you can use both floor and (int) -- but you run into the observed error as soon as the instability of floating point calculations results in a slightly less value -- something in the order of 10-15, for double sized calculations. Use a tiny epsilon value to counteract that.

Note that the epsilon "fudge" value below will relate to the number of significant digits in your original number. For larger numbers, you need a smaller epsilon.

#include <stdio.h>
#include <string.h>
#include <math.h>

int main (void)
{
    double x;
    int z;

    x=pow(64,(1.0/3));
    printf("x=%lf\n",x);
    printf("x=%.30lf\n",x);

    z=(int)x;
    printf("%d\n",z);

    z=(int)(x+0.000000000000005);
    printf("%d\n",z);

    x=pow(64,(1.0/4));
    printf("x=%lf\n",x);
    printf("x=%.30lf\n",x);

    z=(int)x;
    printf("%d\n",z);

    z=(int)(x+0.0000000000000005);
    printf("%d\n",z);

    return 1;
}

results, for powers of 1/3 and 1/4, in

x=4.000000
x=3.999999999999999555910790149937
3
4
x=2.828427
x=2.828427124746190290949243717478
2
2
Jongware
  • 21,058
  • 8
  • 43
  • 86
0

As told by @jongware The int override rounds down and floating point operations may be inaccurate .

though you can always do this to evade this problem

def invpow ( n , i):
    x = pow (n ,(1/i))
    if((int)pow((x+1) , i) <= n):
        x += 1;
    print(x)

Or you can write your own method for exponentiation by using Newton - Raphson method described here and here

you can also use Binary search which is quite fast if you have right guess for the range ie (variables high and low )

def invpow( x, n, low, high){
    if(n==1)
        return x;
    mid=(low+high)/2;

    while(low<high){
        mid=(low+high)/2;

        raised=pw(mid,n);

        if(raised==x)
            break;

        if(raised>x)
            high=mid;
        else
            low=mid;

        if(low+1==high){
            mid=low;
            break;
            }

    }
    return mid;
}
Community
  • 1
  • 1
Namit Sinha
  • 1,345
  • 3
  • 14
  • 29