Struggling to get convergence to Euler's number - matlab

Hi there I’ve been working on trying to plot the convergence of 'e' through using the equation 1/N! with limits from 0 to 9.
clc,clear
terms=[1];
x=10;
for i=2:x
terms(i,1)=terms(i-1,1) + 1/factorial(i);
end
disp(terms)
xplotrange = 0:9;
plot(xplotrange,terms,'b-')
With the code I intened to plot the number of terms in the 'x' axis and the result of the series in the 'y' axis. But I am confused as to why the array of numbers outputted in the for loop converges at 1.718 instead of 2.718?

As #Daniel stated, Euler's number via Taylor expansion should start from x=0 . Thus you can adjust your code to something like below
terms=[1];
x=10;
for i=2:x
terms(i,1)=terms(i-1,1) + 1/factorial(i-1);
end
disp(terms)
xplotrange = 0:9;
plot(xplotrange,terms,'b-')
or a method using cumsum, e.g.,
terms=[1];
x=10;
terms = cumsum(1./factorial(0:x));
disp(terms)
xplotrange = 0:x;
plot(xplotrange,terms,'b-');

Initializing terms with 1 and starting your for loop at 2, you effectively start at i=1, but the sum has to start at i=0. 1/0! is the 1 you are missing.

Related

Suggestion to solve 'NaN' in matlab. Dealing with large and small numbers in Matlab

I am trying to make a model of planets' movement plot it in 3d using Matlab.
I used Newton's law with the gravitational force between two objects and I got the differential equation below:
matlab code:
function dy=F(t,y,CurrentPos,j)
m=[1.98854E+30 3.302E+23 4.8685E+24 5.97219E+24 6.4185E+23 1.89813E+27 5.68319E+26 8.68103E+25 1.0241E+26 1.307E+22];
G=6.67E-11;
dy = zeros(6,1);
dy(1) = y(4);
dy(2) = y(5);
dy(3) = y(6);
for i=1:10
if i~=j
deltaX=(CurrentPos(j,1)-CurrentPos(i,1));
deltaY=(CurrentPos(j,2)-CurrentPos(i,2));
deltaZ=(CurrentPos(j,3)-CurrentPos(i,3));
ray=sqrt((deltaX^2)+(deltaY^2)+(deltaZ^2));
dy(4) = dy(4) + G*m(i)*(deltaX/(ray^3));
dy(5) = dy(5) + G*m(i)*(deltaY/(ray^3));
dy(6) = dy(6) + G*m(i)*(deltaZ/(ray^3));
end
end
where the 'm' array is the planet masses.
then I used the numerical method Runge-Kutta-4 to solve it, and here's the code:
function [y,t]=RK4(F,intPos,a,b,N)
h=(b-a)/N;
t=zeros(N,1);
y = zeros(10*N,6);
y(1,:)=intPos(1,:);
y(2,:)=intPos(2,:);
y(3,:)=intPos(3,:);
y(4,:)=intPos(4,:);
y(5,:)=intPos(5,:);
y(6,:)=intPos(6,:);
y(7,:)=intPos(7,:);
y(8,:)=intPos(8,:);
y(9,:)=intPos(9,:);
y(10,:)=intPos(10,:);
t(1)=a;
for i=1:N
t(i+1)=a+i*h;
CurrentPos=y((i*10)-9:i*10,:);
% CurrentPos(1,:)=intPos(1,:);
y((i*10)+1,:)=intPos(1,:);
for j=2:10
k1=F(t(i),y(((i-1)*10)+j,:),CurrentPos,j);
k2=F(t(i)+h/2,y(((i-1)*10)+j,:)+(h/2).*k1',CurrentPos,j);
k3=F(t(i)+h/2,y(((i-1)*10)+j,:)+(h/2).*k2',CurrentPos,j);
k4=F(t(i)+h,y(((i-1)*10)+j,:)+h.*k3',CurrentPos,j);
y((i*10)+j,:)=y(((i-1)*10)+j,:)+(h/6)*(k1+2*k2+2*k3+k4)';
end
end
Finally applied the function for the Initial States from JPL HORIZONS System:
format short
intPos=zeros(10,6);
intPos(1,:)=[1.81899E+08 9.83630E+08 -1.58778E+07 -1.12474E+01 7.54876E+00 2.68723E-01];
intPos(2,:)=[-5.67576E+10 -2.73592E+10 2.89173E+09 1.16497E+04 -4.14793E+04 -4.45952E+03];
intPos(3,:)=[4.28480E+10 1.00073E+11 -1.11872E+09 -3.22930E+04 1.36960E+04 2.05091E+03];
intPos(4,:)=[-1.43778E+11 -4.00067E+10 -1.38875E+07 7.65151E+03 -2.87514E+04 2.08354E+00];
intPos(5,:)=[-1.14746E+11 -1.96294E+11 -1.32908E+09 2.18369E+04 -1.01132E+04 -7.47957E+02];
intPos(6,:)=[-5.66899E+11 -5.77495E+11 1.50755E+10 9.16793E+03 -8.53244E+03 -1.69767E+02];
intPos(7,:)=[8.20513E+10 -1.50241E+12 2.28565E+10 9.11312E+03 4.96372E+02 -3.71643E+02];
intPos(8,:)=[2.62506E+12 1.40273E+12 -2.87982E+10 -3.25937E+03 5.68878E+03 6.32569E+01];
intPos(9,:)=[4.30300E+12 -1.24223E+12 -7.35857E+10 1.47132E+03 5.25363E+03 -1.42701E+02];
intPos(10,:)=[1.65554E+12 -4.73503E+12 2.77962E+10 5.24541E+03 6.38510E+02 -1.60709E+03];
[yy,t]=RK4(#F,intPos,0,1e8,1e3);
x=zeros(101,1);
y=zeros(101,1);
z=zeros(101,1);
for i=1:1e3
x(i,:)=yy((i-1)*10+4,1);
y(i,:)=yy((i-1)*10+4,2);
z(i,:)=yy((i-1)*10+4,3);
end
plot3(x,y,z)
Finally, the result wasn't satisfying at all and I got many 'NAN', then I did some adjustment on the RK4 method and started to get numbers, but when I plotted them it turned out I'm plotting a line instead of an orbit.
Any help would be appreciated.
Thanks in advance.
Two errors: One physical: The alpha in the formula is the j in the code, the running index j in the formulas is the loop index i in the formula. In total this makes a sign error, transforming the attracting gravity force into a repelling force like between electrons. Thus the physics dictates that the bodies move away from each other almost linearly, as long as their paths don't cross.
Second, you are applying the RK4 method in such a way that in total it is an order 1 method. These also tend to behave un-physically rather quickly. You need to update first all positions to the first stage in a temporary StagePos variable, then use that to compute all position updates for the second stage etc. The difference to the current implementation may be small in each step, but such systematic errors quickly sum up.

Dice simulation with matlab

I am new on this forum. First of all, I find it very interesting to have such a website were everyone can get help in different domains. Thank you very much.
So I have a problem: I was supposed to resolve the following problem:
Simulate with rand ntrials of rolling a dice.
if rand() in [0, 1/6] then 1 was thrown;
if rand() in (1/6, 2/6] then 2 was thrown
...
if rand() in (5/6, 1] then 6 was thrown.
Generate with hist an histogramm of the results of ntrials.
This is what I did:
ntrials = 100;
X = abs(rand(1,ntrials)*6) + 1;
hist(floo(X))
Now there is a second exercise that I must do:
two dice are thrown and S is the sum of the 2 dice
Compute the probability that S respectively accept one of the value 2,3,4,5.....12.
Write a Matlab function twoTimesDice that the theoritical result through a simulation of the throw of 2 dice like in the first exercise.
That is what I tryed:
function twoTimesDice
x1 = abs(rand(1,11))*6 + 1;
s1 = floor(x1); % probably result of the first dice
x2 = abs(rand(1,11))*6 +1;
s2 = floor(x2) % probably result of de second dice
S = s1 +s2;
hist(S);
end
Can you tell me please if I did it well?
Generating a dice roll between 1 and 6 can be done by randi().
So first, use randi() instead of floor() and abs():
X = randi(6,1,ntrials)
which will give you an array of length ntrials with random integers ranging from 1 to 6. (you need the 1 there or it will return a square matrix of size ntrials by ntrials). randi documentation
In the function my personal preference would be to request the number of trials as input.
Your function then becomes:
function twoTimesDice(ntrials)
s1 = randi(6,1,ntrials); % result of the first dice
s2 = randi(6,1,ntrials); % result of the second dice
S = s1 +s2;
hist(S);
end
For a normalised histogram, you can replace hist(S) by:
numOfBins = 11;
[histFreq, histXout] = hist(S, numOfBins);
figure;
bar(histXout, histFreq/sum(histFreq)*100);
xlabel('Value');ylabel('Percentage');
(As described in this question)
For the first part, I would use floor instead of abs,
X = floor(rand(1, ntrials)*6) + 1;
as it returns the values you are looking for, or as Daniel commented, use
randi(6)
which returns an integer.
Then you can just run
hist(X,6)
For the second part, I believe they are asking for two dice rolls, each being 1-6, and not one 2-12.
x = floor(rand(1)*6) + 1;
The distribution will look different. Roll those twice, add the result, that is your twoTimesDice function.
Roll that ntrials times, then do a histogram of that (as you already do).
I am not sure how random rand() really is though.

Using MATLAB to compute all the integers the satisfy a condition

I want to compute using MATLAB all the integers x such that x^2-2x<2000, but I am having problems in the displaying part because when I run my code MATLAB seems not to finish. My code is as follows:
x=100;
while x^2+2x-2000>=10^-6
x=x-20;
if x^2+2x-2000<10^-6
disp(x)
end
end
I think the wrong part is when I type disp(x) in the while loop, but I don't know how to fix it.
NOTE: I am using the 10^-6 to avoid rounding errors
Can someone help me to fix this code please?
Computationally, finding all integers that satisfy this condition will need some help from a quick insight into this problem. Otherwise, you'll have to test all the integers, which is impossible since there is infinite number of integers. Analytically, finding all the integers that satisfy the condition x^2-2x < 2000 means finding the integers that lies within the intersection of the curve x^2 - 2x and y = 2000.
Let's first take a look at the problem by plotting it:
x = -500:.1:500;
y = x.^2 - 2*x;
plot(x, y, 'color', 'g')
hold on
line([-200 200], [2000 2000], 'color', 'r')
You can easily see that you can limit your search to at least between -100 and 100. You can store the value in an array
results = [] % Declare empty array first and append value later.
for x = -100:100
if x^2 - 2*x < 2000
disp(x)
results = [results,x]; % Using a bracket to append value to the array.
end
end
And a faster way to get results using logical indexing.
x = -100:100
results = x(x.^2 - 2*x<2000)
In the above code, x.^2 - 2*x < 2000 generates a logical array that has the same size as x. Each element stores the logical value that comes from the evaluating each element in x with the expression. You then use this as a mask to pick out only elements in x that satisfy this condition.
If you add in some parentheses and use the correct syntax for 2*x, it works.
x=100;
while (x^2+2*x-2000)>= (10^-6)
x=(x-20);
if (x^2+2*x-2000) <10^-6
disp(x)
end
end
Building upon #User3667217's solution, you can also vectorise this:
x = -100:100;
y = x.^2-2*x;
tmp = y<2000;
results = y(tmp);
this will give you a speed up over the for-loop solution.

Matlab: Negative number to the power of n where "n" is bigger than 1 gives an imaginary number

I am running a matlab code in order to solve a matrix in an iterative way, I am trying to solve x=A\b in every iteration until x --> 0 by changing A and b, in the first 3 iterations work fine until I reach a point where I start getting imaginary numbers in my solution.
Here is my code:
Q,H,n,R are predefined variables.
while(eps > 10^-6)
i=1;j=1;
while(i<11)
A11(i,j) = 1.852*R(i)*(abs(Q(i)))^(n-1);
i=i+1;
j=j+1;
end
A11(11,11) = 2*R(11)*abs(Q(11));
%calculate -dE & dq
dE = [200-H(1)-R(1)*Q(1)^1.852
H(1)-H(2)- R(2)*Q(2)^1.852
H(1)-H(3)-R(3)*Q(3)^1.852
H(2)-H(7)-R(4)*Q(4)^1.852
H(6)-H(5)-R(5)*Q(5)^1.852
H(7)-H(4)-R(6)*Q(6)^1.852
H(6)-H(7)-R(7)*(Q(7))^1.852
H(5)-H(4)-R(8)*Q(8)^1.852
H(3)-H(2)-R(9)*Q(9)^1.852
H(3)-H(4)-R(10)*Q(10)^1.852
0-H(3)+240- R(11)*Q(11)];
dq = [-Q(1)+Q(2)+Q(3)
-Q(2)-Q(9)+Q(4)+4
-Q(11)+Q(9)+Q(10)+6
-Q(10)-Q(6)-Q(8)+5
-Q(5)+Q(8)+5
-Q(3)+Q(7)+Q(5)+5
-Q(4)-Q(7)+Q(6)+3];
%formulate the full set of equations
zero=zeros(nn,nn);
b=[dE;dq];
upA = [A11,A12];
downA=[A21,zero];
A= [upA;downA];
%solve the equations (x=A\b)
x = A\b;
%update Q and H
i=1;j=1;
while (i<8 && j<12)
H(i)= x(11+i)+ H(i);
Q(j)= x(j)+ Q(j);
i=i+1;
j=j+1;
end
%check stopping criteria
j=1;sumeps=0;
while (j<12)
sumeps=sumeps+x(j);
j=j+1;
end
epscal = sumeps/12;
eps=abs(epscal)
end
I realized that i start getting problems when one of the values of vector Q turns negative, and when that value is raised to the power of 1.852 (while calculating dE) it gives an imaginary number!!
Maybe someone knows whre
That's correct. (-1)^N has an imaginary component whenever N has a fractional component.
Most obviously, (-1)^0.5 is just i.
It's not the fact hat the power is bigger than 1, it's the fact that the power is not an integer (i.e. X^2, X^3, ...). Imagine X^0.5 which equals sqrt(X). Obviously that yields an imaginary number for negative values of X.

Integration via trapezoidal sums in MATLAB

I need help finding an integral of a function using trapezoidal sums.
The program should take successive trapezoidal sums with n = 1, 2, 3, ...
subintervals until there are two neighouring values of n that differ by less than a given tolerance. I want at least one FOR loop within a WHILE loop and I don't want to use the trapz function. The program takes four inputs:
f: A function handle for a function of x.
a: A real number.
b: A real number larger than a.
tolerance: A real number that is positive and very small
The problem I have is trying to implement the formula for trapezoidal sums which is
Δx/2[y0 + 2y1 + 2y2 + … + 2yn-1 + yn]
Here is my code, and the area I'm stuck in is the "sum" part within the FOR loop. I'm trying to sum up 2y2 + 2y3....2yn-1 since I already accounted for 2y1. I get an answer, but it isn't as accurate as it should be. For example, I get 6.071717974723753 instead of 6.101605982576467.
Thanks for any help!
function t=trapintegral(f,a,b,tol)
format compact; format long;
syms x;
oldtrap = ((b-a)/2)*(f(a)+f(b));
n = 2;
h = (b-a)/n;
newtrap = (h/2)*(f(a)+(2*f(a+h))+f(b));
while (abs(newtrap-oldtrap)>=tol)
oldtrap = newtrap;
for i=[3:n]
dx = (b-a)/n;
trapezoidsum = (dx/2)*(f(x) + (2*sum(f(a+(3:n-1))))+f(b));
newtrap = trapezoidsum;
end
end
t = newtrap;
end
The reason why this code isn't working is because there are two slight errors in your summation for the trapezoidal rule. What I am precisely referring to is this statement:
trapezoidsum = (dx/2)*(f(x) + (2*sum(f(a+(3:n-1))))+f(b));
Recall the equation for the trapezoidal integration rule:
Source: Wikipedia
For the first error, f(x) should be f(a) as you are including the starting point, and shouldn't be left as symbolic. In fact, you should simply get rid of the syms x statement as it is not useful in your script. a corresponds to x1 by consulting the above equation.
The next error is the second term. You actually need to multiply your index values (3:n-1) by dx. Also, this should actually go from (1:n-1) and I'll explain later. The equation above goes from 2 to N, but for our purposes, we are going to go from 1 to N-1 as you have your code set up like that.
Remember, in the trapezoidal rule, you are subdividing the finite interval into n pieces. The ith piece is defined as:
x_i = a + dx*i; ,
where i goes from 1 up to N-1. Note that this starts at 1 and not 3. The reason why is because the first piece is already taken into account by f(a), and we only count up to N-1 as piece N is accounted by f(b). For the equation, this goes from 2 to N and by modifying the code this way, this is precisely what we are doing in the end.
Therefore, your statement actually needs to be:
trapezoidsum = (dx/2)*(f(a) + (2*sum(f(a+dx*(1:n-1))))+f(b));
Try this and let me know if you get the right answer. FWIW, MATLAB already implements trapezoidal integration by doing trapz as #ADonda already pointed out. However, you need to properly structure what your x and y values are before you set this up. In other words, you would need to set up your dx before hand, then calculate your x points using the x_i equation that I specified above, then use these to generate your y values. You then use trapz to calculate the area. In other words:
dx = (b-a) / n;
x = a + dx*(0:n);
y = f(x);
trapezoidsum = trapz(x,y);
You can use the above code as a reference to see if you are implementing the trapezoidal rule correctly. Your implementation and using the above code should generate the same results. All you have to do is change the value of n, then run this code to generate the approximation of the area for different subdivisions underneath your curve.
Edit - August 17th, 2014
I figured out why your code isn't working. Here are the reasons why:
The for loop is unnecessary. Take a look at the for loop iteration. You have a loop going from i = [3:n] yet you don't reference the i variable at all in your loop. As such, you don't need this at all.
You are not computing successive intervals properly. What you need to do is when you compute the trapezoidal sum for the nth subinterval, you then increment this value of n, then compute the trapezoidal rule again. This value is not being incremented properly in your while loop, which is why your area is never improving.
You need to save the previous area inside the while loop, then when you compute the next area, that's when you determine whether or not the difference between the areas is less than the tolerance. We can also get rid of that code at the beginning that tries and compute the area for n = 2. That's not needed, as we can place this inside your while loop. As such, this is what your code should look like:
function t=trapintegral(f,a,b,tol)
format long; %// Got rid of format compact. Useless
%// n starts at 2 - Also removed syms x - Useless statement
n = 2;
newtrap = ((b-a)/2)*(f(a) + f(b)); %// Initialize
oldtrap = 0; %// Initialize to 0
while (abs(newtrap-oldtrap)>=tol)
oldtrap = newtrap; %//Save the old area from the previous iteration
dx = (b-a)/n; %//Compute width
%//Determine sum
trapezoidsum = (dx/2)*(f(a) + (2*sum(f(a+dx*(1:n-1))))+f(b));
newtrap = trapezoidsum; % //This is the new sum
n = n + 1; % //Go to the next value of n
end
t = newtrap;
end
By running your code, this is what I get:
trapezoidsum = trapintegral(#(x) (x+x.^2).^(1/3),1,4,0.00001)
trapezoidsum =
6.111776299189033
Caveat
Look at the way I defined your function. You must use element-by-element operations as the sum command inside the loop will be vectorized. Take a look at the ^ operations specifically. You need to prepend a dot to the operations. Once you do this, I get the right answer.
Edit #2 - August 18th, 2014
You said you want at least one for loop. This is highly inefficient, and whoever specified having one for loop in the code really doesn't know how MATLAB works. Nevertheless, you can use the for loop to accumulate the sum term. As such:
function t=trapintegral(f,a,b,tol)
format long; %// Got rid of format compact. Useless
%// n starts at 3 - Also removed syms x - Useless statement
n = 3;
%// Compute for n = 2 first, then proceed if we don't get a better
%// difference tolerance
newtrap = ((b-a)/2)*(f(a) + f(b)); %// Initialize
oldtrap = 0; %// Initialize to 0
while (abs(newtrap-oldtrap)>=tol)
oldtrap = newtrap; %//Save the old area from the previous iteration
dx = (b-a)/n; %//Compute width
%//Determine sum
%// Initialize
trapezoidsum = (dx/2)*(f(a) + f(b));
%// Accumulate sum terms
%// Note that we multiply each term by (dx/2), but because of the
%// factor of 2 for each of these terms, these cancel and we thus have dx
for n2 = 1 : n-1
trapezoidsum = trapezoidsum + dx*f(a + dx*n2);
end
newtrap = trapezoidsum; % //This is the new sum
n = n + 1; % //Go to the next value of n
end
t = newtrap;
end
Good luck!