2

I am trying to compute the square root of a number using function containing a while loop. Within the conditions of the while loop, I want to compare the absolute value of the ratio of the two values, the guessed square root and the number, to 1. However, whenever I run the program, I keep get an infinite loop outputting 1.414214. Any help? Thanks.

// Function to calculate the absolute value of a number

#include <stdio.h>

float absoluteValue (float x)
{
    if ( x < 0 )
        x = -x;
    return (x);
}

// Function to compute the square root of a number

float   squareRoot (float x, const float epsilon)
{
    float       guess = 1.0;

    while ( absoluteValue ((guess * guess) / x) != epsilon ) {
        guess = ( (x / guess) + guess ) / 2.0;
        printf("%f\n", guess);
    }

        return guess;
}

int main (void)
{
    printf ("squareRoot (2.0) = %f\n", squareRoot (2.0, 1.0));
    printf ("squareRoot (144.0) = %f\n", squareRoot (144.0, 1.0));
    printf ("squareRoot (17.5) = %f\n", squareRoot (17.5, 1.0));

    return 0;
}
Daniel Jour
  • 15,896
  • 2
  • 36
  • 63
  • 2
    Hint: Testing floating point values for exact equality is almost always an error. – Carey Gregory Apr 01 '16 at 00:53
  • 1
    Your loop never ends because the loops condition is not satisfied. Find out why it is not satisfied.or when it should be satisfied. – Imprfectluck Apr 01 '16 at 00:55
  • 1
    Add this to your `while` loop if you want to see why: `printf("%f\n", absoluteValue((guess * guess)/x));` – Carey Gregory Apr 01 '16 at 00:57
  • Note: rather than use `%f`, recommend using `%e` to better see the relative precision of the values you are getting. – chux - Reinstate Monica Apr 01 '16 at 01:39
  • If you are kicking around square root functions, don't pass up a look at [**John Carmack's Unusual Fast Inverse Square Root**](http://stackoverflow.com/questions/1349542/john-carmacks-unusual-fast-inverse-square-root-quake-iii). With a single iteration it is damn close, with 2 it is spot-on, with additional iterations, you exceed the precision of single-precision floating point. All thanks to the need for speed in *surface normal* calculations for 3D graphics. – David C. Rankin Apr 01 '16 at 02:55

1 Answers1

5

Change this:

while ( absoluteValue ((guess * guess) / x) != epsilon ) {

To:

while ( absoluteValue ((guess * guess) / x - 1.0) > epsilon ) {

You want to keep refining your answer until it's within epsilon of the goal. You need to subtract 1.0 from the ratio, to get the difference between what you're seeing and your goal, then you want to stop once the difference is within epsilon. You don't want to keep trying if it's smaller than epsilon.

You will also want to use much smaller values for epsilon, e.g. 0.000001

Tom Karzes
  • 22,815
  • 2
  • 22
  • 41
  • Or `fabs(guess*guess-x) > epsilon` if you want an absolute error tolerance (e.g. +/- 0.01 instead of +/- 1%). – MooseBoys Apr 01 '16 at 01:08
  • @MooseBoys yes, that might be a better way to do it. I was just trying to make the existing test do what was intended. – Tom Karzes Apr 01 '16 at 01:28