Hard Light Productions Forums
Off-Topic Discussion => Programming => Topic started by: Thaeris on April 06, 2010, 02:40:34 pm
-
I usually will say that I hate Matlab hands down, but the symbolic math toolbox is a tremendous asset to use. The project for which this thread is the subject is a bit... overdue, but using Matlab as more of a conventional programming language is nice for a change. Essentially, the program accepts any function in terms of 'x' (and just 'x,' as coded) and uses Newton's Method to find the zeros or roots of the function, at least any root closest to the user input. I'll go over bugs later...
function [ f, df, n, ntest, c, flag ] = NewtonZeros()
syms x f df; %Initialize symbolic math variables.
f = input('Enter a function in terms of x: '); %Input a function 'f' here in terms of 'x.'
df = diff(f, 'x'); %Differentiates function 'f' in terms of 'x.'
n = input('Give an estimate of the function zeroes: '); %Zero or root estimate for 'x' - this value will be sustituted in for 'x.'
flag = 0; %Initializes the loop flag.
c = 0; %Initializes the count value.
while flag ~= 1 %Begin primary loop: looking for closest zero to 'n' input.
n = n - ((subs(f,x,n))/(subs(df,x,n))); %Perform Newton zero function.
if c == 0 %Initiate precision check data insertion.
ntest = n;
end %End data insertion.
c = c + 1; %Augment count.
if c == 4 %Initiate precision check sequence.
ntest = (round( ntest * 100000 )/round( n * 100000 )); %Comparator: precision met if 'ntest' == 1.
if ntest == 1 %Ends loop if comparator precision == 1.
flag = 1;
else % Resets count and data insertion phase if precsion is not met.
c = 0;
end
end %End precision check sequence.
end %End primary loop: value found.
n %Return value.
end
Now, the program will go into an infinite loop if you happen to select a discontinuity and will only find one zero at a time. There certainly must be methods of sorting such problems out, but I think that's beyond the scope of this project. Perhaps I'll finish playing with it at some later date. :)
-
Oh God, why did this take so long to finish?
Regardless, after many hours of pondering on how to optimize the algorithms/code, I finally have a pretty efficient code which bisects a given function to find a function zero:
function [ f, n1, n2, n3, a, b, c ] = BisectZeros()
syms f x; %Initialize symbolic values. This will enable easy function manipulation.
f = input('Enter a function in terms of x: '); %Enables universal usage of function input.
c = 0; %Initialize 'c' for loop test. This variable will be used again later.
while c ~= 1 %'Bound input' tester start.
n1 = input('Give a value for the lower bound of the target region: '); %User enters first x-coordinate value.
n2 = input('Give a value for the upper bound of the target region: '); %User enters second x-coordinate value.
a = subs(f,x,n1); %Initialize 'a' as a test value. This variable will be re-used later.
b = subs(f,x,n2); %Initialize 'b' as a test value. This variable will be re-used later.
if a < 0 %Initiate a process to create a test value for the lower initial bound of the target region.
a = 0;
else
a = 1;
end %Test value for 'n1' established.
if b < 0 %Initiate a process to create a test value for the upper initial bound of the target region.
b = 0;
else
b = 1;
end %Test value for 'n2' established.
if a + b ~= 1 %User feedback function.
disp('The current set of values will not find a function zero. Please select a new set of values.');
else %Only if 'a' + 'b' == 1 will the input tester end, returning 'c' = 1, ending the loop.
c = 1;
end
end %'Bound input' tester restart or end point.
while b ~= 2 %Primary evaluation loop start. By setting the end condition to '2' for variable 'b,' we do not need to add another line to reset the value.
n3 = ( n1 + n2 )/2; %Finds the 'x'-coordinate of the bisection value.
c = subs(f,x,n3); %Redefine 'c' for boolean testing.
if c < 0 %Initiate process to make 'c' a boolean value.
c = 0;
else
c = 1;
end %End process to make 'c' a boolean value.
if a + c == 1 %Initiates 'target bounding region' test.
n2 = n3;
else %This substitues in corresponding logic from the condition 'if b + c == 1, n1 = n3,' where variable 'b' was the one used in the 'bound input tester' loop.
n1 = n3;
end %Ends 'target bounding region' test.
a = subs(f,x,n1); %Variable 'a' is re-used as a value testing function.
if a < 0 %Re-use of variable 'a' as a test value for 'n1.'
a = 0;
else
a = 1;
end %Test value for 'n1' established.
if round( subs(f,x,n3) * 100000 ) == 0 %Precision test conditional checking device. If the zero has been found within the tolerance range, the function ends: 'b' set to '2.'
b = 2;
end
end %End evaluation loop.
n3 %Output.
end
I mean seriously, I feel like a moron. This is simple garbage, but IT TOOK FOR-EVER! :mad:
-
Was there a reason for not using FMINUNC or FZERO?
-
Whoa, that was unexpected. :)
Thanks for dropping in. No, those pre-built functions were not used as the point of the project was to code a solution to finding the zeros by means of more standard coding practices. I kind of... bypassed some of that as I used the symbolic math toolbox (you know, the stuff which almost makes MATLAB cool...) for easy function manipulation - that makes the programs pretty much universal, which was the idea.
Looking back, they are a little buggy depending on the input, and I should have added more checking features if I'd have known what to do at the time. For example, adding a flag tied to a while loop with regards to the function input for the bisection method would have been a good idea (yeah, that's a mouthful...), as using symbolic math's ability to differentiate a function would make you change the function if you accidentally entered a function which was constant (I did that once and had to restart MATLAB...). Using "isnan()" on Newton's method would have let me fix a bug which would leave the program in an infinte loop if you entered the test input as a point of discontinuity. Just little things like that...
The important thing is that the class is over. I got an A in the class, so I'm happy. And I still dislike MATLAB. :p
-
If you want to do symbolic math, I think Mathematica is far better for that than Matlab. However, for what you were trying to do, there is a technique called automatic differentiation that works better than finding symbolic derivatives. There are several free Matlab packages for doing AD.
In practice, zero-finding algorithms use a combination of both of the methods you studied. Bisection is used a few times to get sufficiently close to the zero, followed by Newton's method to get an accurate result.