My Taylor Square Root C Program doesn't like me

Click For Summary

Discussion Overview

The discussion revolves around implementing a C program to calculate the square root of a double precision floating point number using a Taylor series approach. Participants explore the challenges of numerical methods, particularly focusing on convergence issues and potential errors in the implementation.

Discussion Character

  • Homework-related
  • Technical explanation
  • Debate/contested

Main Points Raised

  • One participant describes their attempt to implement a square root function using a Taylor series, noting that their results are not converging as expected.
  • Another participant suggests that the issue may stem from the convergence properties of the Taylor series, specifically that it only converges for certain values of x.
  • A different participant points out potential numerical difficulties with series expansion, including the accumulation of numerical errors and cancellation of significant digits.
  • Concerns are raised about the implementation of the power and factorial functions, with suggestions that recursion might be a more efficient approach.
  • Participants discuss the implications of using integer arithmetic in the power function, questioning whether it could lead to incorrect results.
  • One participant expresses uncertainty about the conceptual validity of their approach, acknowledging the limitations of using a Taylor series for square root calculations.
  • Another participant mentions that, theoretically, sufficient terms in the Taylor series could yield an accurate approximation of the square root, but convergence issues complicate this.

Areas of Agreement / Disagreement

Participants express differing views on the effectiveness of using a Taylor series for calculating square roots, with some suggesting that it may not be suitable while others argue that it could work with enough terms. The discussion remains unresolved regarding the best approach to implement the square root function.

Contextual Notes

Limitations include the potential for numerical errors in series expansion, the dependence on convergence criteria, and unresolved issues in the implementation of the power and factorial functions.

Orcinus
Messages
13
Reaction score
0

Homework Statement


4. Implement a simple method to find the square root of a double precision floating point number x. A simple method is to consider the error produced by a “guess” y of the solution. Square the value y and compare with the value x. If y is correct, the error e=|y2-x| where || is the magnitude will be zero and as the value of y becomes more wrong, the error e will increase. Hence the solution is to home in on the minimum for the error function or some value close enough for our purposes. This problem actually has two solutions +/-y but we can just consider +y. Write a C program to solve this problem using a repetition method. Hint: use a while loop and devise a way to find when you get to the minimum for the error e.

This is in C by the way (Linux gcc) and obviously without using maths libraries.

The question itself is simple, I quickly devised the solution that the question's looking for: http://pastebin.com/cQGzGXN4
But I was curious of doing it another way, and after just learning about Taylor series in maths I wanted to try doing it that way. So far it's not working out so well.

Course: Engineering Programming 100, we've yet to even learn functions yet so yeah I'm going beyond the course and hence beyond my knowledge level.

Homework Equations


I don't know whether this is right, but a plot on www.desmos.com/calculator seems to work
f(x) = \sqrt{x}
<br /> f(x) = 1+ \sum_{n=1}^\infty\frac{\frac{(2n-2)!(-1)^{n-1}(x-1)^n}{2^{2n-1}(n-1)!}}{n!}<br />


The Attempt at a Solution


Here's what I've come up with:
Code:
#include <stdio.h>

double power(double base, int index) //Note that this function does not allow fractional indicies
{
	int x;
	int inverse = 0;
	double result = 1;
	
	if(index<0)
	{
		index = -index;
		inverse = 1;
	}
	if(index==0)
	{
		return 1;
	}
	for(x=0;x<index;x++)
	{
		result = base*result;
	}
	if(inverse == 1)
	{
		return (1/result);
	}
	else
	{
		return result;
	}
}

int factorial(int num)
{
	int x;
	int result = 1;
	for(x=1;x<=num;x++)
	{
		result = result * x;
	}
	return result;
}

double absolute( double num)
{
	double result;
	result = num;
	if(result < 0)
	{
		result = -result;
	}
	return result;
}

double squareroot(double square)
{
	int x = 1;
	double result = 1;
	while(absolute(result*result-square) > 0.000001)
	{ //hello taylor series! I have no idea whether this works.
		result = result + factorial(2*x-2)*power(-1, x-1)/power(2,2*x-1)/factorial(x-1)*power(square - 1, x)/factorial(x);
		x++;
		printf("%lf\n", result);
	}
	return result;
}

int main(void)
{
	double square;
	double result;
	printf("Type the number you'd like to find the square root of: ");
	//scanf("%lf", square);
square = 2; // for debugging
	result = squareroot(square);
	printf("The square root of %lf is %lf.\n", square, result);
	return 0;
}

Note that "printf("%lf\n", result);" in squareroot function and "square = 2; // for debugging" in main function are for debugging purposes. I'm writing this on my tablet so can't compile properly but am using http://codepad.org/W5yNE67K to debug. Hence I manually enter numbers into "square = 2" to test different numbers.

The problem being that my result is coming out nothing like \sqrt{x}, the while loop spits out a NaN for some reason after a while and this brings together so much new stuff for me that I don't know where the problem(s) might lie.
 
Physics news on Phys.org
I think your problem is with the Taylor series. If you check WolframAlpha, you will find that you only get convergence for ##|1-x|<1##.
 
Aaw really? Is that just a thing with square root or is it just my method isn't that great?
 
I'm not a mathematician, but from what I gather it won't work for the square root. Other functions could still be programmed that way.

If you're more interested in general about these kind of numerical methods, I can point two possibile difficulties with series expansion. First, if you implement it naively from ##n=0## to whatever, you are progressively adding smaller and smaller terms, and numerical errors can creep up because of that. This is especially important here, and it touches on my second point, where subsequent terms have different signs, and therefore can cancel each other out. This can also be a problem even when the terms in the series do not progressively decrease, but there is a maximum somewhere in the sum. You can again lose precision if some big term kill off some significant digits before this big term gets canceled out by another big term.

I don't know if you can make sense of what I just wrote. If not, just say so and I will try to come up with specific examples.
 
I should also say that I just had a quick look at your program, and their might be some problems in there too.
 
Yeah for one thing, in the power function, saying return(1/result) will probably give you 0, even though the return type is double. I suspect that it will do the integer arithmetic first, and then cast the result of that to a double, which is not what you want.

Things like power and factorial really lend themselves to *recursion*. You should look it up. It's a technique where a function calls itself.

I could be wrong, but I think that statements like index = -index are inefficient. In any case, you can just write index *= -1.

Regarding the Taylor series: regardless of the value of x, you should be able to get your answer arbitrarily close to sqrt(x) as long as you take enough terms in the sum.

EDIT: oh I didn't think about convergence though. Would have to refresh my memory about that.
 
So the problem was a conceptual one then? That's a shame.
Yeah, I figured that imprecision with floats would come into effect with a series, but I was hoping that (-1)^n might bounce the number around a bit til it was close enough to the right value. But statistics doesn't really let that happen too easily.
So would: "result = 1/result; return result;" make any difference?
I thought x *= y was just the same as x=x*y, shouldn't the compiler recognise that and choose the quickest method?

Well the program conceptually doesn't work, so there's not much point "fixing it". But now I've had a go, do you know where I could find out how <math.h> does it?
 
cepheid said:
Yeah for one thing, in the power function, saying return(1/result) will probably give you 0, even though the return type is double. I suspect that it will do the integer arithmetic first, and then cast the result of that to a double, which is not what you want.
Not in this case. result is declared as a double, so in the division, 1 is promoted to a double value and then the division is performed. If result had been declared as an integral type (e.g., int, long, char, etc.), then 1/result would be calculated using integer division.
cepheid said:
Things like power and factorial really lend themselves to *recursion*. You should look it up. It's a technique where a function calls itself.

I could be wrong, but I think that statements like index = -index are inefficient. In any case, you can just write index *= -1.
Speaking of inefficiency, recursive routines can be much more inefficient than loops, as there is the extra overhead of multiple calls to the recursive function. As far as index = -index vs. index *= -1, I doubt that there is much difference. Also, since this statement is executed only once (as opposed to being executed thousands or more times in a loop), the difference in execution speed would be insignificant.
cepheid said:
Regarding the Taylor series: regardless of the value of x, you should be able to get your answer arbitrarily close to sqrt(x) as long as you take enough terms in the sum.

EDIT: oh I didn't think about convergence though. Would have to refresh my memory about that.
 

Similar threads

  • · Replies 19 ·
Replies
19
Views
3K
  • · Replies 12 ·
Replies
12
Views
3K
  • · Replies 4 ·
Replies
4
Views
2K
  • · Replies 6 ·
Replies
6
Views
2K
  • · Replies 3 ·
Replies
3
Views
2K
  • · Replies 2 ·
Replies
2
Views
3K
  • · Replies 17 ·
Replies
17
Views
3K
  • · Replies 1 ·
Replies
1
Views
2K
  • · Replies 5 ·
Replies
5
Views
4K
  • · Replies 4 ·
Replies
4
Views
3K