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
Related
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;
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
I have a function that should return 2 numbers (geographic coordinates).
Is it possible to get the function to return 2 numbers?
Here is my function (I need to return x and Y)
proc fcmp outlib=common.functions.geo;
function latlng2lambert72(lat,lng);
LongRef = 0.076042943;
bLamb = 6378388 * (1 - (1 / 297));
aCarre = 6378388 ** 2;
eCarre = (aCarre - bLamb ** 2) / aCarre;
KLamb = 11565915.812935;
nLamb = 0.7716421928;
eLamb = sqrt(eCarre);
eSur2 = eLamb / 2;
*conversion to radians;
lat_rad = (constant("pi") / 180) * lat;
lng_rad = (constant("pi") / 180) * lng;
eSinLatitude = eLamb * sin(lat_rad);
TanZDemi = (tan((constant("pi") / 4) - (lat_rad / 2))) *
(((1 + (eSinLatitude)) / (1 - (eSinLatitude))) ** (eSur2));
RLamb = KLamb * ((TanZDemi) ** nLamb);
Teta = nLamb * (lng_rad - LongRef);
x = 150000 + 0.01256 + RLamb * sin(Teta - 0.000142043);
y = 5400000 + 88.4378 - RLamb * cos(Teta - 0.000142043);
*put x y ;
return (x);
*return (x*1000000000000 + y);
*return (x||'_'||y);
endsub;
quit;
data test;
lat = 50.817500;
lng = 4.374400;
x = latlng2lambert72(lat,lng);
run;
I guess not but then the only option I see would be to make 2 functions and have one return the 1st number and the other return the 2nd number. These 2 functions would be 99% identical and I don't like to duplicate code. Is there a more efficient way to achieve this?
(I don't really understand how subroutines work. Could they be used to that end? Execute the common code and just make 2 short functions to return x and y?)
Functions by definition return a single value; that's the definition of a function. It should be able to be on the right hand side of an equal sign.
Subroutines, in SAS known as Call routines, are able to "return" zero, one, or more values. They do this by not returning anything directly (you cannot put a call routine on the right-hand side of an equal sign), but by modifying the arguments they are called with.
You see this in routines like call missing, which can set any number of values to missing; you see it a bit more directly in routines like call scan, which tells you the start position and length of the nth word in a string.
In order to do this, then, you would first want to change your function to a subroutine/call routine, i.e. replace function with subroutine, and then specify OUTARGS.
An example of this would be:
proc fcmp outlib=work.funcs.func;
subroutine roots(inval, outval_pos, outval_neg);
outargs outval_pos,outval_neg; *specifies these two will be "returned";
outval_pos = sqrt(inval);
outval_neg = -1*outval_pos;
endsub;
quit;
options cmplib=work.funcs;
data _null_;
x=9;
call missing(y_pos,y_neg);
call roots(x,y_pos, y_neg);
put x= y_pos= y_neg=;
run;
I have a function to optimize, say Function, in Matlab. This function depends on variables (say x) over which I want to optimize and one parameter (say, Q) which does not need to be optimized.Hence, the function Function(x,Q). In other words, I have an array of values for Q and want to find optimal x values for each Q. However, I cannot find a way how to pass those Q values when using function handle #Function in optimization function.
So, my question is how to pass those Q values when using function handle in optimization functions, for example fmincon(#Function,x0,A,b)?
Try using anonymous function:
x = cell( 1, numel(Q) );
for qi = 1:numel( Q )
x{qi} = fmincon( #(x) Function(x, Q(qi)), A, b );
end
As described in MATLAB documentation, there are actually 3 solutions for this problem:
Anonymous Functions
which is described in the Shai's answer of this post.
Nested Functions:
in this approach the outer function accepts all arguments, and the inner function only accepts parameters that optimization takes place on them.
this is an example taken from MATLAB documentation:
function [x,fval] = runnested(a,b,c,x0)
[x,fval] = fminunc(#nestedfun,x0);
% Nested function that computes the objective function
function y = nestedfun(x)
y = (a - b*x(1)^2 + x(1)^4/3)*x(1)^2 + x(1)x(2) +...
(-c + cx(2)^2)*x(2)^2;
end
end
Global Variables
in this approach you should define the parameters that are needed in objective function as global in workspace, and use them in objective function with declaring them as global.
here is an example again from MATLAB documentation:
Defining objective function:
function y = globalfun(x)
global a b c
y = (a - b*x(1)^2 + x(1)^4/3)*x(1)^2 + x(1)x(2) + ...
(-c + cx(2)^2)*x(2)^2;
end
Optimization:
global a b c;
a = 4; b = 2.1; c = 4; % Assign parameter values
x0 = [0.5,0.5];
[x,fval] = fminunc(#globalfun,x0)
You may be able to do the following:
x = fmincon(fun,x0,A,b,Aeq,beq,lb,ub,nonlcon,options,Q)
which will pass Q along to fun(x,Q)!
Having some trouble declaring functions within my script:
%Read the raw audio data
refData = wavread('file1.wav');
userData = wavread('file2.wav');
% I want to continue writing my "main" function here, and call the below functions
%%%%%%%%%%%%%
% Functions %
%%%%%%%%%%%%%
%Vector x
function preEmphasis(x)
alpha = 0.95;
len = length(x);
for i=1:len
x_i = x(i);
x_iMinus1 = x(i-1);
x(i) = x_i - alpha*x_iMinus1;
end
end
%Vector x
function normalization(x)
maxVal = max(abs(x));
x = x / maxVal;
end
%Vector x; numFrames, frameSize: integers; stepSize: percentage (float, 0.2 -> 0.5 for example)
function Ymatrix = createYmatrix(x, numFrames, frameSize, stepSize)
Ymatrix = zeros(numFrames, frameSize);
for i=1:numFrames
for j=1:frameSize
Ymatrix(i,j) = x(stepSize*i + j);
end
end
end
The words "function" and "end" are highlighted in red as "parse errors". How can I fix this? Thanks.
You can't declare functions within your main script. You have to create an external m-file and implement your function inside it, like it says in the official documentation:
Any function that is not anonymous must be defined within a file.
(just to be clear, a script does not accept input arguments or return output arguments).
However, you can have local functions declared inside a function m-file.
Read more about function declarations in the official documentation.
EDIT: You can Refer to #natan's answer if you're looking for a way to avoid function m-files altogether. He implemented your functions as anonymous functions, which can be declared inside the script file. Good luck!
In Addition to what Eitan mentioned, here is how to implement an anonymous functions in your case, note that code vectorization is a must. For example, in your case instead of normalization you can write:
normalization = #(x) x./max(abs(x));
and then use it as if it was a function, y=normalization(x)
For preEmphasis:
preEmphasis= #(x) [x(1) x(2:end)-0.95*x(1:end-1)];
Your current code has a bug for the case i=1 so I interpret that as for=2:len instead;
The solution for Ymatrix is a bit ugly (haven't invested to much time vectorizing it nicely), but it should work:
Ymatrix = #(x, numFrames, frameSize, stepSize) ...
ones(1,numFrames)'*x(1+stepSize:stepSize+frameSize)+...
meshgrid(0:stepSize:stepSize*numFrames-1,ones(1,frameSize))';
Just turn your script into a function; then you can use local and nested functions. Use return values or assignin if you need to get values back in to the base or caller's workspace.