Solving a function through series (SAS) - function

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;

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

Error in user defined functions with Gp/Pari

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

in SAS proc fcmp how to get 2 numbers returned

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;

as3 Number precision

I am trying to round some numbers in two decimal point and I run into a bizare behavior.
please try the following code:
var num:Number = 30.25
for (var i = 0 ; i < 100 ; i++){
var a:Number = (Math.round(num * 100) / 100)
var b:Number = (Math.round(num * 100) * 0.01 )
trace (num.toString() + " -- " + a.toString() + " -- " + b.toString())
num += 0.999;
}
x = y /100 and x = y * 0.01 should be equal.
(And x = y * 0.01 should be faster).
But if I run the above code the result is not always equal.
I get for example
46.23400000000003 -- 46.23 -- 46.230000000000004
47.23300000000003 -- 47.23 -- 47.230000000000004
48.232000000000035 -- 48.23 -- 48.230000000000004
49.23100000000004 -- 49.23 -- 49.230000000000004
while x=y/100 is always correct x=y*0.01 sometimes adds a small value like 0.000000000000004 at the end.
Am I doing something wrong?
Has anyone else observed this behavior?
In general, in floating point computations you should try to avoid numbers of really different magnitude in the same calculation. That's precisely the issue with these types: the point "floats", so you want to keep the point of one number of the computation close to the point of the other number.
Your question is simply put as
Why is 4623/100 == 46.23 but 4623*0.01 == 46.230000000000004?
For the specific reason, you can dig in the specific of floating point computation, for example here.
4623 is 4.623*10^3 while 0.01 is 1*10^{-3}, notice how the exponent is really different (6 orders of magnitude of difference). While 100 is just 1*10^{2}, much "closer" to 4.623*10^3.

Reduce number of decimals

In AS3, from a division I get a number like this one: 0.9130406010219044.
Is there any way to reduce the number of decimals (aside from multiplying that number for one million)? Is there a way to reduce the numbers BEFORE the division is performed?
Got the following function from this link, which rounds to an arbitrary number of decimals:
public function trim(theNumber:Number, decPlaces:Number) : Number {
if (decPlaces >= 0) {
var temp:Number = Math.pow(10, decPlaces);
return Math.round(theNumber * temp) / temp;
}
return theNumber;
}
// Round a number to two decimal places trace(trim(1.12645, 2));
// Displays: 1.13
Note: I slightly changed the function definition by adding types. See the link for explanation and original source code. Also made it return theNumber if decPlaces is less than or equal to zero.
var myNumber:Number = 74.559832;
trace(myNumber.toFixed(4)); //74.5598
trace(myNumber.toFixed(2)); //74.56
AS3 Documentation: Number class
If you just want to display the result (you didn't specify) then a simple bit of String manipulation will yield the fastest result:
0.9130406010219044.toString().substr(0, 4); // 0.91
Take a look at NumberFormatter.fractionalDigits
Or, if you're working in Flex: mx:NumberFormatter.precision / s:NumberFormatter.fractionalDigits
Try some of the answers here on for size:
How to deal with Number precision in Actionscript?
If you use a NumberFormatter, make sure to specify rounding (it's most likely you'll want nearest).
If you need Number as result and performance, I would say this solution is more efficient than the Math.pow()
If you need 3 decimals just change 100 by 1000.
var myNumber:Number = 3.553366582;
myNumber = (( myNumber * 100 + 0.5) >> 0) / 100;
//trace = 3.55
demonstrating the rounding :
var myNumber:Number = 3.557366582;
myNumber = (( myNumber * 100 + 0.5) >> 0) / 100;
//trace = 3.56
Regarding the Number.toFixed() returning a String I guess it's because it returns 2 decimals in any case:
For instance :
Number(3).toFixed(2); // trace 3.00 so it has to be a String.