Error in user defined functions with Gp/Pari - function

I'm trying to work on learning the Gp Pari programing language, and I'm working through project Euler problems and I can't seem to get it to compile right :( It's supposed to calculate a list of all Fibonacci numbers of size less than some input n.
here's the code,
Euler_2(n) =
(
x = 0;
y = 0;
fib = listcreate(n);
listput(fib,1);
listput(fib,1);
a = True;
while(a,
{if( x > n,
a = False;
);
x = fib[#fib] + fib[#fib-1];
listput(fib,x);
}); \\ end the while loop
)\\ end the function
I'm completely new at this language (I know a fair amount of python). Any helpful comments would be great! Thanks in advance!

You need to surround the code with braces, not parentheses, to use multiple lines. (You can also use line-ending backslashes, as Shawn suggests in a comment, but that gets old fast.) A quick code review:
Euler_2(n) =
{
\\ always declare lexical variables with my()
my(x = 0, y = 0, fib = List([1, 1]), a = 1);
while(1, \\ loop forever
x = fib[#fib] + fib[#fib-1];
listput(fib,x);
if(x > n, break);
); \\ end the while loop
Vec(fib); \\ not sure what you wanted to return -- this returns the list, converted to a vector
} \\ end the function

Related

Result of recursive function in Verilog

My math may not be serving me well. I've written a simple recursive function in Verilog to calculate value of log base 2. Log2(1000) should return 9.965 rounded to 10. But, my simulation shows that the function returns 9 as the final value of the recursive function. Any idea what I'm doing wrong?
module test;
real numBits;
function real log2 (input int X);
if (X == 1)
log2 = 0.0;
else begin
log2 = log2(X / 2) + 1.0;
$display($stime,,,"log2 = %0d",log2);
end
endfunction
initial begin
numBits = log2(1000);
$display($stime,,,"numBits = %f",numBits);
end
endmodule
Here's the EDA playground link that shows the code:
https://www.edaplayground.com/x/icx7
A couple of problems with your code. The first is the input to your function needs to be real. Then, it's never good to compare real numbers with equality do to rounding errors. Use X<=1 instead. And finally you should declare recursive functions with an automatic lifetime so that the arguments and the return values do not get overwritten.
function automatic real log2 (input real X);
if (X <= 1)
log2 = 0.0;
else begin
log2 = log2(X / 2) + 1.0;
$display($stime,,,"log2 = %0g",log2);
end
endfunction

Why does Octave not encapsule variables inside of nested functions?

When writing nested functions in Octave, the variables do not seem to be encapsuled:
function r = asd()
fn1();
endfunction
function res1 = fn1()
res1 = 0;
function res2 = fn2()
res2 = 0;
for i = 10:20
res2 = res2 + i;
endfor
endfunction
for i = 1:10
printf("i before calling fn2(): %d\n", i);
res1 = res1 + fn2();
printf("i after calling fn2(): %d\n", i);
endfor
endfunction
This seems very odd to me because it screams for bugs, right? Is there a specific reason the variables are not encapsuled here?
Nested functions exist explicitly to share variables with the enclosing function. This is their purpose. If you don’t want a private function to share variables with the calling function, declare it after the calling function in the same M-file. This makes it a “local function”, a function only visible from within this file.
In general nested functions are weird and should only be used in specific circumstances. One place they are useful is to encapsulate variables in a more complex lambda than can be accomplished with an anonymous function:
% Returns a function that depends on x
function f = createLambda(x)
y = atan(x); % some calculation
function res = nested(val)
res = y * val; % …but this would be several lines or a loop or whatever
end
f = #nested
end
Nested functions exist in Octave because they were introduced in MATLAB. You should read the excellent MATLAB documentation to learn more about them.

Solving a function through series (SAS)

I need some help in checking my program in SAS that uses loops to solve a function as i am struggling. The function which i need to solve is in terms of a series expansion and it is:
ln(1+x)
I need to evaluate the function at x0 = 0.8 and the summation must stop when the next term is less than 0.05.
This is what I have so far but I'm very far off from where I need to be I believe:
data sumseries;
numerator = x;
denom =1;
x = 0.8;
do while (tot>abs(0.05));
numerator=x*numerator;
denom=denom+1;
sign=sign*-1
term=numerator/denom;
tot=sign*tot+term;
output;
end;
proc print data=sumseries;
run;
Any help is greatly appreciated!
Edit: Apologies if my formatting/presentation of the coding etc isn't up to scratch as I'm not familiar with this site
Edit: Change of names/values but replied answer still stands
I'll first give you pointers with your method, then provide my preferred solution.
Your solution, updated with my fixes:
data q2;
*indent please!;
denom =1;
x = 0.3;
*Move this assignment to after x is assigned;
numerator= x;
*initialize sign;
sign = 1;
*initialize tot;
tot=x;
*need an output to start out with;
output;
*WHILE change to UNTIL (req. switching > to <);
*tot changed to term;
do until (term < abs(0.000001));
numerator=x*numerator;
denom=denom+1;
sign=sign*-1;
term=numerator/denom;
*you want to add (sign*term) to the total, right?;
tot=tot + sign*term;
output;
end;
*always include a RUN after data steps, even though not required;
run;
proc print data=q2;
run;
My preferred solution:
*Use the macro language to define things like starting values;
%let x=0.3;
*let us see how close we get to correct!;
%put %sysfunc(log(1.3));
data want;
*initialize sum;
sum = 0;
*loop until we hit the limit. The until here is technically unneeded;
*but I like to include it for clarity;
do term = 1 by 1 until (abs(new) lt 1e-6);
*make the new value to be added (x to the power of term, divided by term;
*times -1 to the power of term plus one to get the right value for the sign);
new = (((&x)**term)/term) * (-1)**(term+1);
*stop iterating if the new term would be too small;
if abs(new) lt 1e-6 then leave;
*add to the sum now and output;;
sum = sum + new;
output;
end;
stop; *stop the data step loop;
run;
You might want to not output that last line, by the way, but that should be easy to add.
You can use the DIF function to compare the difference between two items that are FIFO stacked.
Example:
Presume the fuzz (1e-5) will be reached within 100 iterations.
data quotient;
x = 0.3;
guard = 100;
numerator = 1;
denom = 0;
sign = -1;
sum = 0;
* Mercator series:
* ln(1+x) = x^1/1 - x^2/2 + x^3/3 - x^4/4 + ... ;
ln_1_3 = log(1+0.3);
do iteration = 1 to guard until (iteration > 1 and abs(dif(sum)) < 1e-5);
numerator = x * numerator;
denom = denom + 1;
sign = sign * -1;
term = sign * numerator / denom;
sum = sum + term;
output;
end;
stop;
run;
proc print data=q2;
run;

Pointer to MATLAB function?

So I have a for-loop in MATLAB, where either a vector x will be put through one function, say, cos(x).^2, or a different choice, say, sin(x).^2 + 9.*x. The user will select which of those functions he wants to use before the for-loop.
My question is, I dont want the loop to check what the user selected on every iteration. Is there a way to use a pointer to a function, (user defined, or otherwise), that every iteration will use automatically?
This is inside a script by the way, not a function.
Thanks
You can use function_handles. For your example (to run on all available functions using a loop):
x = 1:10; % list of input values
functionList = {#(x) cos(x).^2, #(x) sin(x).^2 + 9*x}; % function handle cell-array
for i=1:length(functionList)
functionOut{i} = functionList{i}(x); % output of each function to x
end
You can try something like the following:
userChoice = 2;
switch userChoice
case 1
myFun = #(x) sin(x).^2 + 9.*x;
case 2
myFun = #(x) cos(x).^2;
end
for k = 1:10
x(k,:) = myFun(rand(1,10));
end

MatLab - nargout

I am learning MatLab on my own, and I have this assignment in my book which I don't quite understand. Basically I am writing a function that will calculate sine through the use of Taylor series. My code is as follows so far:
function y = sine_series(x,n);
%SINE_SERIES: computes sin(x) from series expansion
% x may be entered as a vector to allow for multiple calculations simultaneously
if n <= 0
error('Input must be positive')
end
j = length(x);
k = [1:n];
y = ones(j,1);
for i = 1:j
y(i) = sum((-1).^(k-1).*(x(i).^(2*k -1))./(factorial(2*k-1)));
end
The book is now asking me to include an optional output err which will calculate the difference between sin(x) and y. The book hints that I may use nargout to accomplish this, but there are no examples in the book on how to use this, and reading the MatLab help on the subject did not make my any wiser.
If anyone can please help me understand this, I would really appreciate it!
The call to nargout checks for the number of output arguments a function is called with. Depending on the size of nargout you can assign entries to the output argument varargout. For your code this would look like:
function [y varargout]= sine_series(x,n);
%SINE_SERIES: computes sin(x) from series expansion
% x may be entered as a vector to allow for multiple calculations simultaneously
if n <= 0
error('Input must be positive')
end
j = length(x);
k = [1:n];
y = ones(j,1);
for i = 1:j
y(i) = sum((-1).^(k-1).*(x(i).^(2*k -1))./(factorial(2*k-1)));
end
if nargout ==2
varargout{1} = sin(x)'-y;
end
Compare the output of
[y] = sine_series(rand(1,10),3)
and
[y err] = sine_series(rand(1,10),3)
to see the difference.