Continuous fraction approximation of pi - matlab

While studying for Matlab, I came up with this problem: given an integer 1<d<15 find the smallest p,q (positive integers) such that abs(p/q-pi)<=10^-d.
So here's my attempt: I first thought that I need to bound p,q in order to create loops, so I put as input data some M,Nupper bounds for p,q respectively. So here is my algorithm:
M=input('Give an upper bound for p:')
N=input('Give an upper bound for q:')
d=input('Give a positive integer between 1 and 15:')
for q=1:N
for p=1:M
if abs(pi-p/q)<=10^(-d)
break
end
end
end
What is wrong about it?
Thank you in advance.

The problem lies in the the way you chose to terminate the for loops: break only stops the inner loop. Try this code instead, and check the value of p and q at which the execution stops:
M=input('Give an upper bound for p:')
N=input('Give an upper bound for q:')
d=input('Give a positive integer between 1 and 15:')
for q=1:N
for p=1:M
if abs(pi-p/q)<=10^(-d)
[p,q]
error('Found!') % Arrest the program when condition is met
end
end
end
which gives the following output:
Of course, there are better ways of capturing all the possible pairs of integers that meet the condition (e.g. by using disp instead of error). That goes beyond the scope of this answer, but I shall provide a couple of examples here:
clear; clc;
M=input('Give an upper bound for p:')
N=input('Give an upper bound for q:')
d=input('Give a positive integer between 1 and 15:')
pairs = []; % p,q pairs are stored here
k = 1; % counter
for q=1:N
for p=1:M
if abs(pi-p/q)<=10^(-d)
pairs(k,1) = p;
pairs(k,2) = q;
k = k + 1; % increment the counter
end
end
end
The script above will end quietly: the (p,q) pairs will be stored in the pair matrix.
The following one will print directly the pairs:
clear; clc;
M=input('Give an upper bound for p:')
N=input('Give an upper bound for q:')
d=input('Give a positive integer between 1 and 15:')
for q=1:N
for p=1:M
if abs(pi-p/q)<=10^(-d)
out = sprintf("(%d, %d)", p,q);
disp(out);
end
end
end
For the sake of the experiment, and following up on #Cris Luengo's comment, here's a slightly more elaborate version of the script: the for loops are encapsulated in a dedicated function and a while loop keeps good track of the progress and populates the res matrix with the (p,q) pairs:
clear; clc;
M=input('Give an upper bound for p:');
N=input('Give an upper bound for q:');
d=input('Give a positive integer between 1 and 15:');
close_to_pi = #(px,qx) abs(pi-px/qx)<=10^(-d); % returns true/false
p = 1; q = 1;
count = 0;
res = nan(N*M,2) ; % (p,q) pairs are stored here; preallocate for speed!
tic % starts the timer
while (q <= N)
[p,q, found] = approx_pi(p, q, N, M, close_to_pi);
if found
count = count + 1;
res(count,:) = [p,q]; % populates output var
end
if p<M % we aren't done with p
p = p + 1;
else % reset p and increment q
p = 1;
q = q + 1;
end
end
res(isnan(res(:,1)),:) = []; % gets rid of the empty elements
disp(count)
toc % stops the timer and prints elapsed time
function [p, q, found] = approx_pi(p0, q0, N, M, fun)
for q=q0:N
for p=p0:M
if fun(p,q)
found = 1;
return
end % if
end % for p
p0 = 1;
end % for q
found = 0;
end % approx_pi
If you are interested in continuous fraction approximations of pi, try rat(pi, Tol) where Tol is the tolerance. Further details here.

Related

Deflation in eigenvalue and eigenvector computation

Using this method, I should be able to get eigenvalues by getting the greatest value in each iteration.
But, what my code enables to get is only the first eingenvalue (and not necessarily the greatest) and I don't know where is the problem.
function [Vect,Vp]=PID(A,precision)
nbVal= 50;
[n,m]=size(A);
X=zeros(n,1);
X(1,1)=1;
Vect=zeros(n,min(n,nbVal));
Vp=zeros(1,min(n,nbVal));
XG=zeros(1,n);
j=1;
for i=1:min(nbVal,n)
Y = rand(n,1);
while (max(abs(Y/norm(Y)-X/norm(X))>=precision))
X=Y/norm(Y);
Y=A*X;
end
Vect(:,i)=X;
% To prevent a division by 0
while (X(j,1)==0 && j<=n)
j = j + 1;
end
if X(j,1)~=0
Vp(1,i) =Y(j,1)/X(j,1);
end
% Wielandt Deflation
YG= rand(1,n);
while (max(abs(YG/norm(YG)-XG/norm(XG)))>=precision )
XG=YG/norm(YG);
YG=XG*A;
end
A2=A-Vp(1,i)*(X*XG)/(XG*X);
A=A2;
end
end

Need help looping for different values of tolerance for Successive over relaxation method

I wrote the following code for a Successive over-relaxation method where it gives me the no. of iterations it took to give me the answer for a certain tolerance value.
I want help in adjusting this code so that I can get the answer for different values of tolerances i.e. [10^-4, 10^-6, 10^-8, 10^-10, 10^-12]
I know I need to put a for loop outside the existing while loop but I cannot figure out how. Can someone help me with this, please?
N=100;
ID = 30177207;% ENTER YOUR STUDENT ID HERE
[A,b]= set_A(ID,N);
xnew=linspace(0,0,length(A))';
n=size(xnew,1);
normVal=Inf;
nmax=1000; %number of maximum iterations which can be reached%
tol= 10^-4; % Tolerence for method%
iter=0;
omega = 1.7;
while normVal>tol && iter<nmax
x_old=xnew;
for i=1:n
sum1 = 0;
sum2 = 0;
for j=1:i-1 % sum the terms involving "new" values
sum1 = sum1 + A(i,j)*xnew(j);
end
for j=i+1:n % sum the terms involving "old" values
sum2 = sum2 + A(i,j)*x_old(j);
end
xnew(i) = (b(i) - sum1 - sum2)/A(i,i); % new value of x(i)
xnew = (1-omega)+ omega*xnew; %relaxation, so for omega = 1 it will give same answer as the gauss seidel method
end
iter=iter+1;
normVal=norm(x_old-xnew);
end
fprintf('Solution of the system is in %d iterations',iter);
I cannot run your code, but since you have an iterative method that runs while normVal > tol what you can do is to iterate over decreasing values of tol, and every time you leave the while loop you will have the solution within the given tolerance possibly you have the same solution for different tolerances.
N=100;
ID = 30177207;% ENTER YOUR STUDENT ID HERE
[A,b]= set_A(ID,N);
xnew=linspace(0,0,length(A))';
n=size(xnew,1);
normVal=Inf;
nmax=1000; %number of maximum iterations which can be reached%
tol= 10^-4; % Tolerence for method%
iter=0;
omega = 1.7;
for tol = [10^-4, 10^-6, 10^-8, 10^-10, 10^-12]
while normVal>tol && iter<nmax
x_old=xnew;
for i=1:n
sum1 = 0;
sum2 = 0;
for j=1:i-1 % sum the terms involving "new" values
sum1 = sum1 + A(i,j)*xnew(j);
end
for j=i+1:n % sum the terms involving "old" values
sum2 = sum2 + A(i,j)*x_old(j);
end
xnew(i) = (b(i) - sum1 - sum2)/A(i,i); % new value of x(i)
xnew = (1-omega)+ omega*xnew; %relaxation, so for omega = 1 it will give same answer as the gauss seidel method
end
iter=iter+1;
normVal=norm(x_old-xnew);
end
fprintf('here you have a solution for tol = %g', tol);
end

Output Argument Not Assigned During Call: Matlab

I am attempting to generate 2500 psuedo-random numbers using LCG for a project. However, when I attempt to run the code I continuously receive the error "Output argument 'p' (and maybe others) not assigned during call to lcgg'.". I was hoping someone could help me understand why p is not in the output and how I can fix this?
clear;
clc;
M = 2500;
ID = 801201076;
disp('N = '); disp(mod(ID,3));
[A,p1] = lcgg(M,30269,171,0,1);
[B,p2] = lcgg(M,30307,172,0,1);
[C,p3] = lcgg(M,30323,170,0,1);
disp('Period = '); disp(p2);
% Combine the 3 generators as in Wichmann and Hill
figure(1);
subplot(2,1,1);hist(B);title('Histogram for Uniform RDN from LCG');
subplot(2,1,2);qqplot(rand(300,1),B);title('QQplot for uniform RDN from LCG');
figure(2);
scatter(B(1:(M-1),1),B(2:M,1),4);title('Plot of sequential pairs for LCG');
D = A + B + C - fix(A + B + C); % internal Matlab uniform random number generator
u = rand(M,1); % internal Matlab uniform random number generator
figure(3);
subplot(2,1,1);scatter(u(1:(M-1),1),u(2:M,1),4);title('Plot of Sequential Pairs for Matlab Internal Generator');
subplot(2,1,2);scatter(D(1:M-1),1),D(2:M,1),4;title('Plot of sequential pairs for 3 LCG Combined')
% Calculate the period
i = 1;
j = 2;
while A(i,1) ~= A(j,1) && i < m
if j < m
j = j+1;
else
i = i+1;
j = j+1;
end
end
if i == m
p = m;
else
p = j-1;
end
A = A./m;
if M <= m
A = A(1:M,:);
end
function[A,p] = lcgg(M,m,a,c,x0)
% Generates a matrix of random numbers using lcg
% Calculate the period
% Input: M: total number of random numbers needed
% m, a, x, x0
% Output: A: M * 1 matrix of random numbers
% p: period of the LCG random number generator
A = zeros(m,1);
for i = 1:m
if i == 1
A(i,1) = lcg(m,a,c,x0);
else
A(i,1) = lcg(m,a,c,A(i-1,1));
end
end
end
% The LCG Function:
function[x] = lcg(m,a,c,x0)
% Linear Congruential Generator (LCG)
x = mod(a*x0+c, m);
end
You define a function:
function[A,p] = lcgg(...)
Within the function body you need to assign a value to both output variables, A and p. You don’t assign anything to p, hence the message.

How to solve the "Array indices must be positive integers or logical values" when using optimization toolbox?

I am trying to implement this optimization problem through optimization toolbox:
where N = 60 files and K = 130 users when 1/K ≤ M ≤ t∗N/K, for which t∗ =3.
so I wrote this code:
clear all;
close all;
clc;
N=60;
t=3;
K=130;
for M=0:0.1:1.4
r=zeros(size(1:M));
f=le(1/K,M);
c=le(M,3*N/K);
if f || c
R2 = #(s) -(s-(s./ floor(N./s)).*M);
LB = 1;
UB = min(N, K);
options = optimoptions('fmincon','Algorithm','interior-point'); % run interior-point algorithm
[sopt, ropt] = fmincon(R2,1,[],[],[],[],LB,UB,[],options);
r(M) = -ropt;
end
end
plot(0:1.4,r(M),'r-','LineWidth',2);
xlabel('Cache Capacity (M)');
ylabel('Delivery Rate (R)');
However the output should be as shown in the graph the one of cut-set bound
The error is as follows:
Array indices must be positive integers or logical values.
Error in try (line 17)
r(M) = -ropt;
First define r outside of the for loop
r =zeros(size(0:0.1:1.4));
To index r inside the for loop you need integer, M is a float Number.
you can just define an additional index i
Also you don't need to specify r indices while plotting if you want
to plot the entire array, and remember to keep the abscissa as
0:0.1:1.4
The code is as follow
N=60;
t=3;
K=130;
i = 0;
r = zeros(size(0:0.1:1.4));
for M=0:0.1:1.4
i = i+1;
f=le(1/K,M);
c=le(M,3*N/K);
if f || c
R2 = #(s) -(s-(s./ floor(N./s)).*M);
LB = 1;
UB = min(N, K);
options = optimoptions('fmincon','Algorithm','interior-point'); % run interior-point algorithm
[sopt, ropt] = fmincon(R2,1,[],[],[],[],LB,UB,[],options);
r(i) = -ropt;
end
end
plot(0:0.1:1.4,r,'r-','LineWidth',2);
xlabel('Cache Capacity (M)');
ylabel('Delivery Rate (R)');
Alternatively you just can predefine all M elements as M = 0:0.1:1.4, then loop around using integer index, that can be used also in indexing r
The corresponding code is as follow
N=60;
t=3;
K=130;
M = 0:0.1:1.4;
r = zeros(size(M));
for i = 1:length(M)
f=le(1/K,M(i));
c=le(M(i),3*N/K);
if f || c
R2 = #(s) -(s-(s./ floor(N./s)).*M(i));
LB = 1;
UB = min(N, K);
options = optimoptions('fmincon','Algorithm','interior-point'); % run interior-point algorithm
[sopt, ropt] = fmincon(R2,1,[],[],[],[],LB,UB,[],options);
r(i) = -ropt;
end
end
plot(0:0.1:1.4,r,'r-','LineWidth',2);
xlabel('Cache Capacity (M)');
ylabel('Delivery Rate (R)');
Graph

How to add a Sequence of Estimates to my Newton Raphson Code for matlab?

My code works BUT I need to add 2 more things:
output- a vector containing the sequence of estimates including the initial guess x0,
input- max iterations
function [ R, E ] = myNewton( f,df,x0,tol )
i = 1;
while abs(f(x0)) >= tol
R(i) = x0;
E(i) = abs(f(x0));
i = i+1;
x0 = x0 - f(x0)/df(x0);
end
if abs(f(x0)) < tol
R(i) = x0;
E(i) = abs(f(x0));
end
end
well, everything you need is pretty much done already and you should be able to deal with it, btw..
max iteration is contained in the variable i, thus you need to return it; add this
function [ R, E , i] = myNewton( f,df,x0,tol )
Plot sequence of estimates:
plot(R); %after you call myNewton
display max number of iterations
disp(i); %after you call myNewton