Order of convergence Newton - matlab

Hello I have written this to determine a root using Newton's method. The algorithm works. I also tried to implement an Experimental order of convergence EOC. It also works but I get the result that the order of convergence for Newton's method is 1 when in fact it is 2.
function [x,y,eoc,k]=newnew(f,df,x0,xe,eps,kmax)
x = x0;
y = feval(f,x);
for m=1:kmax
z = -y/feval(df,x);
x = x + z;
y = feval(f,x);
k = m;
for n=m
Ek=abs(x-xe);
end
for n=m+1
Ekp=abs(x-xe);
end
eoc=log(Ek)/log(Ekp);
if abs(y)<eps
return
end
end
disp('no convergence');
end
what is wrong?

When you say Ek=abs(x-xe) and Exp=abs(x-xe), they are exactly the same thing! That's why eoc evaluates to 1 every time.
Notice that you have no n in those equations. In fact, you don't need those extra for n=m loops either. Inside the for m=1:kmax loop, m is a single value not an array.
eoc needs to be calculated by comparing the previous loop iteration to the current one (since it doesn't make much sense to compare to a future loop iteration which hasn't happened yet). Because this looks like homework, I won't give you any code.. but this is a very strong hint.

Related

Make vector of elements less than each element of another vector

I have a vector, v, of N positive integers whose values I do not know ahead of time. I would like to construct another vector, a, where the values in this new vector are determined by the values in v according to the following rules:
- The elements in a are all integers up to and including the value of each element in v
- 0 entries are included only once, but positive integers appear twice in a row
For example, if v is [1,0,2] then a should be: [0,1,1,0,0,1,1,2,2].
Is there a way to do this without just doing a for-loop with lots of if statements?
I've written the code in loop format but would like a vectorized function to handle it.
The classical version of your problem is to create a vector a with the concatenation of 1:n(i) where n(i) is the ith entry in a vector b, e.g.
b = [1,4,2];
gives a vector a
a = [1,1,2,3,4,1,2];
This problem is solved using cumsum on a vector ones(1,sum(b)) but resetting the sum at the points 1+cumsum(b(1:end-1)) corresponding to where the next sequence starts.
To solve your specific problem, we can do something similar. As you need two entries per step, we use a vector 0.5 * ones(1,sum(b*2+1)) together with floor. As you in addition only want the entry 0 to occur once, we will just have to start each sequence at 0.5 instead of at 0 (which would yield floor([0,0.5,...]) = [0,0,...]).
So in total we have something like
% construct the list of 0.5s
a = 0.5*ones(1,sum(b*2+1))
% Reset the sum where a new sequence should start
a(cumsum(b(1:end-1)*2+1)+1) =a(cumsum(b(1:end-1)*2+1)+1)*2 -(b(1:end-1)+1)
% Cumulate it and find the floor
a = floor(cumsum(a))
Note that all operations here are vectorised!
Benchmark:
You can do a benchmark using the following code
function SO()
b =randi([0,100],[1,1000]);
t1 = timeit(#() Nicky(b));
t2 = timeit(#() Recursive(b));
t3 = timeit(#() oneliner(b));
if all(Nicky(b) == Recursive(b)) && all(Recursive(b) == oneliner(b))
disp("All methods give the same result")
else
disp("Something wrong!")
end
disp("Vectorised time: "+t1+"s")
disp("Recursive time: "+t2+"s")
disp("One-Liner time: "+t3+"s")
end
function [a] = Nicky(b)
a = 0.5*ones(1,sum(b*2+1));
a(cumsum(b(1:end-1)*2+1)+1) =a(cumsum(b(1:end-1)*2+1)+1)*2 -(b(1:end-1)+1);
a = floor(cumsum(a));
end
function out=Recursive(arr)
out=myfun(arr);
function local_out=myfun(arr)
if isscalar(arr)
if arr
local_out=sort([0,1:arr,1:arr]); % this is faster
else
local_out=0;
end
else
local_out=[myfun(arr(1:end-1)),myfun(arr(end))];
end
end
end
function b = oneliner(a)
b = cell2mat(arrayfun(#(x)sort([0,1:x,1:x]),a,'UniformOutput',false));
end
Which gives me
All methods give the same result
Vectorised time: 0.00083574s
Recursive time: 0.0074404s
One-Liner time: 0.0099933s
So the vectorised one is indeed the fastest, by a factor approximately 10.
This can be done with a one-liner using eval:
a = eval(['[' sprintf('sort([0 1:%i 1:%i]) ',[v(:) v(:)]') ']']);
Here is another solution that does not use eval. Not sure what is intended by "vectorized function" but the following code is compact and can be easily made into a function:
a = [];
for i = 1:numel(v)
a = [a sort([0 1:v(i) 1:v(i)])];
end
Is there a way to do this without just doing a for loop with lots of if statements?
Sure. How about recursion? Of course, there is no guarantee that Matlab has tail call optimization.
For example, in a file named filename.m
function out=filename(arr)
out=myfun(in);
function local_out=myfun(arr)
if isscalar(arr)
if arr
local_out=sort([0,1:arr,1:arr]); % this is faster
else
local_out=0;
end
else
local_out=[myfun(arr(1:end-1)),myfun(arr(end))];
end
end
end
in cmd, type
input=[1,0,2];
filename(input);
You can take off the parent function. I added it just hoping Matlab can spot the recursion within filename.m and optimize for it.
would like a vectorized function to handle it.
Sure. Although I don't see the point of vectorizing in such a unique puzzle that is not generalizable to other applications. I also don't foresee a performance boost.
For example, assuming input is 1-by-N. In cmd, type
input=[1,0,2];
cell2mat(arrayfun(#(x)sort([0,1:x,1:x]),input,'UniformOutput',false)
Benchmark
In R2018a
>> clear all
>> in=randi([0,100],[1,100]); N=10000;
>> T=zeros(N,1);tic; for i=1:N; filename(in) ;T(i)=toc;end; mean(T),
ans =
1.5647
>> T=zeros(N,1);tic; for i=1:N; cell2mat(arrayfun(#(x)sort([0,1:x,1:x]),in,'UniformOutput',false)); T(i)=toc;end; mean(T),
ans =
3.8699
Ofc, I tested with a few more different inputs. The 'vectorized' method is always about twice as long.
Conclusion: Recursion is faster.

while loop until certain condition on the function value is met

I'm trying to fit some data with Matlab, using the least square method.
I found best fit parameters, and I want to determine the uncertainty on them now.
To determine the uncertainty on the first parameter, say a, we have seen in course that one should apply a variation to one parameter, until the difference between the function (evaluated at that variation) minus the original function value equals 1.
That is, I have a vector called [bestparam] in my Matlab code, containing the four parameters a, b, c and d.
I also have a function defined in another file, called chi-square, which I evaluated at the best parameters.
I now want to apply a small variation to the parameter a, and keep doing this until chi-square(a + variation) - chi-square = 1. The difference must be exactly one. I implemented for this the following code:
i = 0;
a_new = a + i;
%small variation on the parameter a
new_param = [a_new b c d];
%my new parameters at which I want the function chisquare to be evaluated
newchisquare = feval(#chisquare, [new_param], X, Y, dY);
%the function value
while newchisquare - chisquarevalue ~= 1
i = i + 0.0001;
a_new = a_new + i;
new_param = [a_new b c d];
newchisquare = feval(#chisquare, [new_param], X, Y, dY);
end
disp(a_new);
disp(newchisquare);
But when I execute this loop, it never stops running. When I change the condition to < 1, i.e. that the difference should be larger than one, then it does stop after like 5 seconds. But then the difference between the function values is no longer exactly one. For example, my original function value is 63.5509 and the new one is then 64.6145 which is not exactly 1 larger.
So is there some way to implement the code, and to keep updating the parameter a until the difference is exactly one? Help is appreciated.
Performing numerical methods I wouldn't recommend using operations like == or ~= unless you are sure that you are comparing two integers. Only small deviations of your value may cause your code to never stop. You can apply some tolerance treshold to make your code stop if it is approximately correct:
TOL = 1e-2;
while (abs(newchisquare - chisquarevalue) <= 1 - TOL)
% your code
end

Basic structure of a for loop

I am trying to write a MATLAB function that accepts non-integer, n, and then returns the factorial of it, n!. I am supposed to use a for loop. I tried with
"for n >= 0"
but this did not work. Is there a way how I can fix this?
I wrote this code over here but this doesn't give me the correct answer..
function fact = fac(n);
for fact = n
if n >=0
factorial(n)
disp(n)
elseif n < 0
disp('Cannot take negative integers')
break
end
end
Any kind of help will be highly appreciated.
You need to read the docs and I would highly recommend doing a basic tutorial. The docs state
for index = values
statements
end
So your first idea of for n >= 0 is completely wrong because a for doesn't allow for the >. That would be the way you would write a while loop.
Your next idea of for fact = n does fit the pattern of for index = values, however, your values is a single number, n, and so this loop will only have one single iteration which is obviously not what you want.
If you wanted to loop from 1 to n you need to create a vector, (i.e. the values from the docs) that contains all the numbers from 1 to n. In MATLAB you can do this easily like this: values = 1:n. Now you can call for fact = values and you will iterate all the way from 1 to n. However, it is very strange practice to use this intermediary variable values, I was just using it to illustrate what the docs are talking about. The correct standard syntax is
for fact = 1:n
Now, for a factorial (although technically you'll get the same thing), it is clearer to actually loop from n down to 1. So we can do that by declaring a step size of -1:
for fact = n:-1:1
So now we can find the factorial like so:
function output = fac(n)
output = n;
for iter = n-1:-1:2 %// note there is really no need to go to 1 since multiplying by 1 doesn't change the value. Also start at n-1 since we initialized output to be n already
output = output*iter;
end
end
Calling the builtin factorial function inside your own function really defeats the purpose of this exercise. Lastly I see that you have added a little error check to make sure you don't get negative numbers, that is good however the check should not be inside the loop!
function output = fac(n)
if n < 0
error('Input n must be greater than zero'); %// I use error rather than disp here as it gives clearer feedback to the user
else if n == 0
output = 1; %// by definition
else
output = n;
for iter = n-1:-1:2
output = output*iter;
end
end
end
I don't get the point, what you are trying to do with "for". What I think, what you want to do is:
function fact = fac(n);
if n >= 0
n = floor(n);
fact = factorial(n);
disp(fact)
elseif n < 0
disp('Cannot take negative integers')
return
end
end
Depending on your preferences you can replace floor(round towards minus infinity) by round(round towards nearest integer) or ceil(round towards plus infinity). Any round operation is necessary to ensure n is an integer.

Solving for the square root by Newton's Method

yinitial = x
y_n approaches sqrt(x) as n->infinity
If theres an x input and tol input. Aslong as the |y^2-x| > tol is true compute the following equation of y=0.5*(y + x/y). How would I create a while loop that will stop when |y^2-x| <= tol. So every time through the loop the y value changes. In order to get this answer--->
>>sqrtx = sqRoot(25,100)
sqrtx =
7.4615
I wrote this so far:
function [sqrtx] = sqrRoot(x,tol)
n = 0;
x=0;%initialized variables
if x >=tol %skips all remaining code
return
end
while x <=tol
%code repeated during each loop
x = x+1 %counting code
end
That formula is using a modified version of Newton's method to determine the square root. y_n is the previous iteration and y_{n+1} is the current iteration. You just need to keep two variables for each, then when the criteria of tolerance is satisfied, you return the current iteration's output. You also are incrementing the wrong value. It should be n, not x. You also aren't computing the tolerance properly... read the question more carefully. You take the current iteration's output, square it, subtract with the desired value x, take the absolute value and see if the output is less than the tolerance.
Also, you need to make sure the tolerance is small. Specifying the tolerance to be 100 will probably not allow the algorithm to iterate and give you the right answer. It may also be useful to see how long it took to converge to the right answer. As such, return n as a second output to your function:
function [sqrtx,n] = sqrRoot(x,tol) %// Change
%// Counts total number of iterations
n = 0;
%// Initialize the previous and current value to the input
sqrtx = x;
sqrtx_prev = x;
%// Until the tolerance has been met...
while abs(sqrtx^2 - x) > tol
%// Compute the next guess of the square root
sqrtx = 0.5*(sqrtx_prev + (x/sqrtx_prev));
%// Increment the counter
n = n + 1;
%// Set for next iteration
sqrtx_prev = sqrtx;
end
Now, when I run this code with x=25 and tol=1e-10, I get this:
>> [sqrtx, n] = sqrRoot(25, 1e-10)
sqrtx =
5
n =
7
The square root of 25 is 5... at least that's what I remember from maths class back in the day. It also took 7 iterations to converge. Not bad.
Yes, that is exactly what you are supposed to do: Iterate using the equation for y_{n+1} over and over again.
In your code you should have a loop like
while abs(y^2 - x) > tol
%// Calculate new y from the formula
end
Also note that tol should be small, as told in the other answer. The parameter tol actually tells you how inaccurate you want your solution to be. Normally you want more or less accurate solutions, so you set tol to a value near zero.
The correct way to solve this..
function [sqrtx] = sqRoot(x,tol)
sqrtx = x;%output = x
while abs((sqrtx.^2) - x) > tol %logic expression to test when it should
end
sqrtx = 0.5*((sqrtx) + (x/sqrtx)); %while condition prove true calculate
end
end

Matlab while looping; a function within a function

How do i loop a function inside another function until both sides equal each other ?
for example
after I find this "f"
f = (1/(-1.8*log(((epsilon/D)/3.7)^2 + 6.9/Re)))^2;
I want to use that value of f and input it here
f = (1/ -2.0*log((epsilon/D) + (2.51/Re*sqrt(***f***))))^2
the program is supposed to loop until both sides equal each other or are relatively close. the acceptable accuracy or error is 0.00001.
and how do I display that value of f that gives mme wha
It seems to me you are trying to solve an expression
f = somefun(f);
where the initial value for f is given by
f = (1/(-1.8*log(((epsilon/D)/3.7)^2 + 6.9/Re)))^2
Your best bet (if it's available to you) is to use Matlab's optimization toolbox, where you set the function to be minimized to
f - somefun(f)
and where you can set the tolerance using optimset('TolFun', 1e-5);
If you don't have the toolbox, then drN's suggestion in the comments of using Newton's method is probably as good as any -and you will learn more from doing it yourself.
I'm assuming that's fix point iteration you are attempting to use there, with your first code line being a starting estimate and your second code line being the actual fixed point iteration.
In this case you need to simply repeat that second statement while testing the difference between successive iterations. Something like this for example.
f = 1;
df = 1;
while abs(df) > 0.0001
fnew = log(20/f);
df = fnew - f;
f = fnew;
end;
BTW. The above is a simple example of fixed point iteration to solve f*exp(f)=20, [or equivalently f = ln(20/f)]. Apply the same logic to your particular equation for "f", but beware that not all equations are amenable to fixed point iteration.