I have been trying to create an implementation of the secant method in C/C++, but I seem to be coming across a few problems. I don't know if my code is erroneous or I am misunderstanding the algorithm itself.
> ln(x) is undefined for x <= 0. It is never even supposed to reach this point.
you are throwing a line by two points of the curve.
If you keep in mind that the derivative of your function is `1/x' you may realise that the derivative decreases rapidly (close to 0) and if your two test points are too big you'll intersect the x axis in the negative values.
Your initial approximation should be "close enough" to the root (by instance, use binary search), in your case you don't converge because you fail outside of the domain of the function (yet another check)
@Duoas
I was told previously by someone else that I should be recursing with c as well as a or b (whichever is closest to c).
What do you mean by not converging? This has just four iterations until the error appears.
@ne555
I can't keep in mind the derivative since the method isn't supposed to need it. What do you mean by "use binary search"? How would that help?
on line 7 you make use of the comma operator so I wonder if fa = f(a) won't be evaluated, only the variable fa might be created. I am not sure about this though, but you may be able to humour me for a minute, and put those 2 statements on separate lines. It is good practice to declare and initialise to something 1 variable per line.
Also, won't you need some logic to cover if your function f() returns negative, or at least cover if the sign changes?
A minor thing - you are using fabs(), c++ has std::abs() (in <cmath> )which is overloaded to handle various types.
@shoulderman
You were told wrong. Don't waste time or energy playing with a or b.
Remember, a=xn-2 and b=xn-1.
The next iterations's (a,b) should be xn-1, xn... which are (b,c).
Also, a prerequisite is that f be differentiable, or continuous. The secant method does not require you to know f′, but it must exist.
And x0 and x1 need to be well-chosen -- somewhere that f is more-or-less linear and crosses the x-axis.
@TheIdeasMan
Line 7 is fine, though I agree that, stylistically speaking, it is better to put each declaration on its own line. [edit] It's not the comma operator in this case. [/edit]
It doesn't matter if f() returns negative. (Most functions with roots do return negative.)
> I can't keep in mind the derivative since the method isn't supposed to need it.
I was trying to explain how you may fall outside the domain
> What do you mean by "use binary search"? How would that help?
You need a good initial approximation, x0 and x1 should be near the root https://en.wikipedia.org/wiki/Bisection_method may help you refine them
@Duoas
C1 is how many iterations are allowed and C2 is epsilon. For my implementation, only C2 is applicable.
I don't really understand what the actual problem is.
This is some code I found on another website implementing the secant method:
1 2 3 4 5 6 7 8 9 10 11 12 13
double secant(double a, double b)
{
do
{
double fa = f.f(a), fb = f.f(b);
if (fa == fb) exit(-1);
double c = b - ((fb * (b - a)) / (fb - fa));
a = b;
b = c;
} while (fabs(b - a) > EPSILON);
return b;
}
This does not work for ln(x) between [0.1, 50]. Why is this? What do I do when c becomes negative?
I apologize for my lack of understanding, but I've never really worked with this method before.
Remember, the function does not constrain itself to working only inside the interval [a,b]. That's just the starting point.
If you use 50 as a starting point, then the line crosses the x-axis somewhere to the left of 0, which is outside your function's domain.
As ne555 indicated, the typical way of implementing a root finder with this method is to start with the bisection method to get a pretty good choice for (a, b), and then use the secant method to quickly refine it.