views:

210

answers:

7

I wrote a program to calculate nth root of a number upto 2 decimal places. eg 4th root of 81 is 3., 3rd root of 125 is 5.Its working nicely except for the 2nd root of 4. It's giving the output 1.99 instead of 2. Here is the code.

#include<stdio.h>
int main(int argc, char **argv)
{
    double root1(int,int);
    int n;
    int num1;
    double root;
    printf("\n\n-----------This is the programme to find the nth root of a number-----------\n\n");
    printf("Enter a nuber greater then 1 : ");
    scanf("%d",&num1);
    if(num1>1)
    {
        printf("Enter the value for 'n'(the root to be calculated) : ");
        scanf("%d",&n);
        root = root1(num1,n);
        printf("%d th Root of %d is %f\n\n", n,num1,root);
    }
    else
        printf("wrong entry");
    return 0;
}

double root1(int a, int b)
{
    int j;
    double i,k;
    double incre = 0.01;
    for(i=1; i<=a; i = i+incre)
    {
        for(j=0;j<b;j++)
        {
            k=k*i;
        }
        if(a<k)
        {
            return(i-incre);
            break;
        }
        else
            k=1;
    }
}

I have tried it for hours, but can't rectify it. can anybody debug this?? I will be very thankful.

+3  A: 

The answer, as with most floating-point problems, is that C works with a limited precision. And floats are binary. They can't exactly represent the decimal number 1.99 - it will likely be a close value like 1.990000000023.....

Standard link for these problems: What Every Computer Scientist Should Know About Floating-Point

There's luckily an easy solution (but not perfect!). Find the root of (num*10000.0), using increments of one. This will be of course 100 times the root that you really want. Hence, the last two digits are the "decimal places" you wanted. You'll find that the root of 40000.0 is precisely 200.0 This works because 1.0 can be perfectly represented.

The price you pay for for precision at that end is that you lose it on the other end - multiplying by 10000 means you'll get a loss of precision with higher numbers. Easy solutions rarely come without drawbacks, sorry.

MSalters
but why it's not going upto 2. My condition for break is a<k. if we input a = 4 then the value of k is square of 1.99. So it can't be greater then 4. Why the loop is breaking?
Same thing. It can't represent the number `0.01` either. It will something like be `0.009999999999984...`. Hence, 0.01 + 0.01 will be `0.019999999999968...` . And 0.01 + 0.01 + 0.01 + 0.01 (times 199) will cause 198 rounding errors.
MSalters
Thanks buddy. All these information are very useful for me.
+5  A: 

That's because computers can't handle real numbers properly.

http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems

klez
More specifically, computers can't handle *infinite precision*. All objects, including all numbers, which includes all floating-point numbers, are represented by a finite set of bytes.
Loadmaster
@Loadmaster: even more specifically: computers handle indefinite precision as humans do: symbolically.
Richard
+3  A: 

Well, if you want 0.01 accuracy, you need step 0.005 or less, and then perform rounding. The best way is to just use pow(num1, 1/n) :-)

BarsMonster
Thanks guys. All of you are very helpful but I think I have to use gdb for this. I will check the assembly.May be I will get something there.
A: 

Doubles cannot necessarily represent floating point numbers accurately. Try using a decimal datatype instead (if c has such a think, sorry can't remember). C# has decimal, Java has BigDecimal classes to represent floating point numbers accurately.

Simon
+1  A: 

what MSalters said. try making incre smaller to see how the value gradually approaches 2.0. you might want to have a higher "internal" precision (ie incre) that what you return, and round the internal result to, say, 2 digits. This way you might cover those rounding problems (but it's just an untested suspicion)

Nicolas78
It doesn't work, in fact more rounding errors will accumulate. He currently has 199 rounding errors, all at 1up. Decreasing the increment to 0.001 means you'll have 1999 rounding errors, still at 1 up. Now 1up of 0.001 is a bit smaller, but it's hardly progress. Also, you're adding 1998 times instead of 198 times, which again means you have more but smaller rounding errors.
MSalters
+7  A: 
Richard
dude, you made my day.
A: 

A smaller "incre" value should work, I used 0.001 and root1 returned 2.00 for the square root of 4.

Also, if you want the answer to be displayed to 2 decimal places, use %.2f when you print the root.

matthew.vooght