Conor
Conor

Reputation: 45

Why does this code fail for these weird numbers?

I wrote a function to find the cube root of a number a using the Newton-Raphson method to find the root of the function f(x) = x^3 - a.

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

double cube_root(double a)
{
    double x = a;
    double y;
    int equality = 0;

    if(x == 0)
    {
        return(x);
    }

    else
    {
        while(equality == 0)
        {
            y = (2 * x * x * x + a) / (3 * x * x);

            if(y == x)
            {
                equality = 1;
            }

            x = y;

        }

    return(x);

    }
}

f(x) for a = 20 (blue) and a = -20 (red) http://graphsketch.com/?eqn1_color=1&eqn1_eqn=x*x*x%20-%2020&eqn2_color=2&eqn2_eqn=x*x*x%20%2B%2020&eqn3_color=3&eqn3_eqn=&eqn4_color=4&eqn4_eqn=&eqn5_color=5&eqn5_eqn=&eqn6_color=6&eqn6_eqn=&x_min=-8&x_max=8&y_min=-75&y_max=75&x_tick=1&y_tick=1&x_label_freq=5&y_label_freq=5&do_grid=0&bold_labeled_lines=0&line_width=4&image_w=850&image_h=525

The code seemed to be working well, for example it calculates the cube root of 338947578237847893823789474.324623784 just fine, but weirdly fails for some numbers for example 4783748237482394? The code just seems to go into an infinite loop and must be manually terminated.

Can anyone explain why the code should fail on this number? I've included the graph to show that, using the starting value of a, this method should always keep providing closer and closer estimates until the two values are equal to working precision. So I don't really get what's special about this number.

Upvotes: 0

Views: 47

Answers (2)

gnasher729
gnasher729

Reputation: 52538

Apart from posting an incorrect formula...

You are performing floating point arithmetic, and floating point arithmetic has rounding errors. Even with the rounding errors, you will get very very close to a cube root, but you won't get exactly there (usually cube roots are irrational, and floating point numbers are rational).

Once your x is very close to the cube root, when you calculate y, you should get the same result as x, but because of rounding errors, you may get something very close to x but slightly different instead. So x != y. Then you do the same calculation starting with y, and you may get x as the result. So your result will forever switch between two values.

You can do the same thing with three numbers x, y and z and quit when either z == y or z == x. This is much more likely to stop, and with a bit of mathematics you might even be able to proof that it will always stop.

Better to calculate the change in x, and determine whether that change is small enough so that the next step will not change x except for rounding errors.

Upvotes: 2

cakefactory
cakefactory

Reputation: 56

shouldn't it be:

y = x - (2 * x * x * x + a) / (3 * x * x);

?

Upvotes: 1

Related Questions