Hi everyone,
I tried to use the code below to solve r in the bove equation.
Could you please have a look at what is the issue in the attached SAS code?
Thank you very much for your help.
KindRegards,
Mac
Hi @MAC1430,
I think the reason for the "Read Access Violation" exception is that you're using array references B[0] (i.e., with index 0) in the definition of function h. Unlike arrays in a DATA step, arrays in PROC FCMP are always 1-based (see the remark about "lower-bound specifications" in the documentation), so the array indices of array B cannot match the corresponding variable "subscripts" (starting at 0). But you can define the array B so that B[1]=B0, B[2]=B1 and so on. This is exactly what your ARRAY statement
array B[*] B0-B11;
later in the DATA steps does.
The correction is a simple shift (by +1) of the indices i of the array references B[i] in the definition of function h:
c11= 11*p-B[1]*(F[1]+1)+B[2];
c10= -10*F[1]*B[1]-F[2]*B[2]-10*B[1]+9*B[2]+B[3]+55*p;
c9= -45*B[1]*(F[1]+1)+B[2]*(36-9*F[2])+B[3]*(8-F[3])+165*p+B[4];
c8= -120*B[1]*(F[1]+1)+B[2]*(84-36*F[2])+B[3]*(28-8*F[3])+330*p+(7-F[4])*B[4]+B[5];
c7= -210*B[1]*(F[1]+1)+B[2]*(126-84*F[2])+B[3]*(56-28*F[3])+B[5]*(6-F[5])+462*p+(21-7*F[4])*B[4]+B[6];
c6= -252*B[1]*(F[1]+1)+B[2]*(126-126*F[2])+B[3]*(70-56*F[3])+B[6]*(5-F[6])+B[5]*(15-6*F[5])+462*p+(35-21*F[4])*B[4]+B[7];
c5= -210*B[1]*(F[1]+1)+B[2]*(84-126*F[2])+B[3]*(56-70*F[3])+B[5]*(20-15*F[5])+B[6]*(10-5*F[6])+B[7]*(4-F[7])+330*p+35*B[4]*(1-F[4])+B[8];
c4= -120*B[1]*(F[1]+1)+B[2]*(36-84*F[2])+B[3]*(28-56*F[3])+B[5]*(15-20*F[5])+B[6]*(10-10*F[6])+B[7]*(6-4*F[7])+B[8]*(3-F[8])+165*p+B[4]*(21-35*F[4])+B[9];
c3= -45*B[1]*(F[1]+1)+B[2]*(9-36*F[2])+B[3]*(8-28*F[3])+B[5]*(6-15*F[5])+B[6]*(5-10*F[6])+B[7]*(4-6*F[7])+3*B[8]*(1-F[8])+B[9]*(2-F[9])+55*p+7*B[4]*(1-3*F[4])+B[10];
c2= -10*B[1]*(F[1]+1)+B[2]*(1-9*F[2])+B[3]*(1-8*F[3])+B[5]*(1-6*F[5])+B[6]*(1-5*F[6])+B[7]*(1-4*F[7])+B[8]*(1-3*F[8])+B[9]*(1-2*F[9])+B[10]*(1-F[10])+11*p+B[4]*(1-7*F[4])+B[11];
c1= -F[1]*B[1]-F[2]*B[2]-F[3]*B[3]-F[5]*B[5]-F[6]*B[6]-F[7]*B[7]-F[8]*B[8]-F[9]*B[9]-F[10]*B[10]-F[11]*B[11]-B[1]+p-F[4]*B[4]+B[12];
c0= -F[12]*B[12];
The original function has poles at r=-1 and r=0. Therefore, the IF condition in the definition of function xrate2 should be extended (cf. the solution in your earlier thread where the function had poles at r=-1 and r=g):
if min(abs(1+r),abs(r))<1e-4 then r=.; /* avoid poles of the original function */
Of course, if solutions like r=0.00009 are considered valid and useful, you should modify the criterion correspondingly (e.g., use a smaller upper bound like 1e-5).
After the above changes your code runs without issues (except for the trivial "Invalid data" notes in the creation of your sample data, as ballardw has already mentioned). The comment after the definition of array init should now read
/* Up to 12 roots are possible theoretically. */
... although for your current sample data at most one solution is found. Only 89 observations have non-missing values for all parameters. Among these, only 3 have a solution in variable r1 of dataset WANT. There are cases where r=0 or values very close to zero would be solutions if such were admissible (example: stock='BE0003810273' & year=2016). The good news is that those three solutions pass the check shown below:
data sel;
set want;
where r1>.;
run;
proc fcmp outlib=work.funcs.test;
function m(r, p, B[*], F[*]);
u=1+r;
s1=p-B[1];
do t=1 to 11;
s1 = s1 - (F[t]-r)/u**t*B[t];
end;
z = s1 - (F[t]-r)/r/u**11*B[12];
return(z);
endfunc;
run;
data check;
set sel;
array B[*] B0-B11;
array F[*] F1-F12;
diff=m(r1, p, B, F);
run;
proc print data=check;
var stock year r1 diff;
run;
Result:
Obs stock year r1 diff
1 AT0000606306 2014 0.67999 -3.4596E-8
2 BE0003565737 2009 0.59515 6.96638E-11
3 BE0974264930 2017 0.01498 1.878618E-9
I've checked one of the 89−3=86 cases with no solutions (in the interval (0, 1)) -- stock='AT0000606306' & year=2012 -- and found that the polynomial in this case has indeed no root in (0, 1), only one negative root (-0.006...) and one >10. You may want to check a few more of these cases, but I see no indications that the results might be incorrect. (I haven't checked the definitions of c0, c1, etc. in detail, though. At least the results in dataset CHECK are consistent with the assumption that you did a great job in calculating them.)
First thing, your data step generates hundreds of invalid data messages.
Replace the text NA in the numeric values with a . to read missing values correctly.
I get this error from your FCMP procedure code, do you?
ERROR: An exception has been encountered. Please contact technical support and provide them with the following traceback information: The SAS task name is [FCMP] ERROR: Read Access Violation FCMP Exception occurred at (3222DF2E) Task Traceback Address Frame (DBGHELP API Version 4.0 rev 5) 000000003222DF2E 000000003168D570 sascmpa:tkvercn1+0x11CEEE 0000000032242A01 000000003168D630 sascmpa:tkvercn1+0x1319C1 000000003223A215 000000003168D6C0 sascmpa:tkvercn1+0x1291D5 0000000032239249 000000003168D7C0 sascmpa:tkvercn1+0x128209 000000003223A3C2 000000003168D850 sascmpa:tkvercn1+0x129382 00000000322391A0 000000003168D950 sascmpa:tkvercn1+0x128160 000000003223A3C2 000000003168D9E0 sascmpa:tkvercn1+0x129382 00000000322391A0 000000003168DAE0 sascmpa:tkvercn1+0x128160 000000003223811D 000000003168DB90 sascmpa:tkvercn1+0x1270DD 0000000032237C99 000000003168E0C0 sascmpa:tkvercn1+0x126C59 000000003220A757 000000003168E140 sascmpa:tkvercn1+0xF9717 000000003220B765 000000003168E1D0 sascmpa:tkvercn1+0xFA725 0000000032209401 000000003168E280 sascmpa:tkvercn1+0xF83C1 0000000032207445 000000003168E370 sascmpa:tkvercn1+0xF6405 0000000032213E84 000000003168E460 sascmpa:tkvercn1+0x102E44 0000000032226212 000000003168E660 sascmpa:tkvercn1+0x1151D2 00000000322131AB 000000003168E810 sascmpa:tkvercn1+0x10216B 0000000032212BA1 000000003168E920 sascmpa:tkvercn1+0x101B61 000000003218744A 000000003168E9D0 sascmpa:tkvercn1+0x7640A 000000003218D7D3 000000003168EA20 sascmpa:tkvercn1+0x7C793 00000000321FBD51 000000003168EB10 sascmpa:tkvercn1+0xEAD11 0000000032185052 000000003168F560 sascmpa:tkvercn1+0x74012 0000000032183604 000000003168F6A0 sascmpa:tkvercn1+0x725C4 0000000030EB19B2 000000003168F6A8 sasfcmp:tkvercn1+0x972 000000000316946E 000000003168FBB8 sashost:Main+0x113BE 000000000316F2CD 000000003168FF20 sashost:Main+0x1721D 00007FF923DD7034 000000003168FF28 KERNEL32:BaseThreadInitThunk+0x14 00007FF925C22651 000000003168FF58 ntdll:RtlUserThreadStart+0x21 NOTE: The SAS System stopped processing this step because of errors. NOTE: PROCEDURE FCMP used (Total process time): real time 0.50 seconds cpu time 0.25 seconds
If you get such a message it often means that you have some issue that is so severe that SAS didn't write a syntax check for it.
Strongly suggest that you use replace all the addition in the FCMP code with the SUM function. You have so many missing values you are extremely likely to get missing values for one or more of the elements of any of those C variables. Which will mean the C variable is missing unless that is your intent.
Hi @MAC1430,
I think the reason for the "Read Access Violation" exception is that you're using array references B[0] (i.e., with index 0) in the definition of function h. Unlike arrays in a DATA step, arrays in PROC FCMP are always 1-based (see the remark about "lower-bound specifications" in the documentation), so the array indices of array B cannot match the corresponding variable "subscripts" (starting at 0). But you can define the array B so that B[1]=B0, B[2]=B1 and so on. This is exactly what your ARRAY statement
array B[*] B0-B11;
later in the DATA steps does.
The correction is a simple shift (by +1) of the indices i of the array references B[i] in the definition of function h:
c11= 11*p-B[1]*(F[1]+1)+B[2];
c10= -10*F[1]*B[1]-F[2]*B[2]-10*B[1]+9*B[2]+B[3]+55*p;
c9= -45*B[1]*(F[1]+1)+B[2]*(36-9*F[2])+B[3]*(8-F[3])+165*p+B[4];
c8= -120*B[1]*(F[1]+1)+B[2]*(84-36*F[2])+B[3]*(28-8*F[3])+330*p+(7-F[4])*B[4]+B[5];
c7= -210*B[1]*(F[1]+1)+B[2]*(126-84*F[2])+B[3]*(56-28*F[3])+B[5]*(6-F[5])+462*p+(21-7*F[4])*B[4]+B[6];
c6= -252*B[1]*(F[1]+1)+B[2]*(126-126*F[2])+B[3]*(70-56*F[3])+B[6]*(5-F[6])+B[5]*(15-6*F[5])+462*p+(35-21*F[4])*B[4]+B[7];
c5= -210*B[1]*(F[1]+1)+B[2]*(84-126*F[2])+B[3]*(56-70*F[3])+B[5]*(20-15*F[5])+B[6]*(10-5*F[6])+B[7]*(4-F[7])+330*p+35*B[4]*(1-F[4])+B[8];
c4= -120*B[1]*(F[1]+1)+B[2]*(36-84*F[2])+B[3]*(28-56*F[3])+B[5]*(15-20*F[5])+B[6]*(10-10*F[6])+B[7]*(6-4*F[7])+B[8]*(3-F[8])+165*p+B[4]*(21-35*F[4])+B[9];
c3= -45*B[1]*(F[1]+1)+B[2]*(9-36*F[2])+B[3]*(8-28*F[3])+B[5]*(6-15*F[5])+B[6]*(5-10*F[6])+B[7]*(4-6*F[7])+3*B[8]*(1-F[8])+B[9]*(2-F[9])+55*p+7*B[4]*(1-3*F[4])+B[10];
c2= -10*B[1]*(F[1]+1)+B[2]*(1-9*F[2])+B[3]*(1-8*F[3])+B[5]*(1-6*F[5])+B[6]*(1-5*F[6])+B[7]*(1-4*F[7])+B[8]*(1-3*F[8])+B[9]*(1-2*F[9])+B[10]*(1-F[10])+11*p+B[4]*(1-7*F[4])+B[11];
c1= -F[1]*B[1]-F[2]*B[2]-F[3]*B[3]-F[5]*B[5]-F[6]*B[6]-F[7]*B[7]-F[8]*B[8]-F[9]*B[9]-F[10]*B[10]-F[11]*B[11]-B[1]+p-F[4]*B[4]+B[12];
c0= -F[12]*B[12];
The original function has poles at r=-1 and r=0. Therefore, the IF condition in the definition of function xrate2 should be extended (cf. the solution in your earlier thread where the function had poles at r=-1 and r=g):
if min(abs(1+r),abs(r))<1e-4 then r=.; /* avoid poles of the original function */
Of course, if solutions like r=0.00009 are considered valid and useful, you should modify the criterion correspondingly (e.g., use a smaller upper bound like 1e-5).
After the above changes your code runs without issues (except for the trivial "Invalid data" notes in the creation of your sample data, as ballardw has already mentioned). The comment after the definition of array init should now read
/* Up to 12 roots are possible theoretically. */
... although for your current sample data at most one solution is found. Only 89 observations have non-missing values for all parameters. Among these, only 3 have a solution in variable r1 of dataset WANT. There are cases where r=0 or values very close to zero would be solutions if such were admissible (example: stock='BE0003810273' & year=2016). The good news is that those three solutions pass the check shown below:
data sel;
set want;
where r1>.;
run;
proc fcmp outlib=work.funcs.test;
function m(r, p, B[*], F[*]);
u=1+r;
s1=p-B[1];
do t=1 to 11;
s1 = s1 - (F[t]-r)/u**t*B[t];
end;
z = s1 - (F[t]-r)/r/u**11*B[12];
return(z);
endfunc;
run;
data check;
set sel;
array B[*] B0-B11;
array F[*] F1-F12;
diff=m(r1, p, B, F);
run;
proc print data=check;
var stock year r1 diff;
run;
Result:
Obs stock year r1 diff
1 AT0000606306 2014 0.67999 -3.4596E-8
2 BE0003565737 2009 0.59515 6.96638E-11
3 BE0974264930 2017 0.01498 1.878618E-9
I've checked one of the 89−3=86 cases with no solutions (in the interval (0, 1)) -- stock='AT0000606306' & year=2012 -- and found that the polynomial in this case has indeed no root in (0, 1), only one negative root (-0.006...) and one >10. You may want to check a few more of these cases, but I see no indications that the results might be incorrect. (I haven't checked the definitions of c0, c1, etc. in detail, though. At least the results in dataset CHECK are consistent with the assumption that you did a great job in calculating them.)
Registration is now open for SAS Innovate 2025 , our biggest and most exciting global event of the year! Join us in Orlando, FL, May 6-9.
Sign up by Dec. 31 to get the 2024 rate of just $495.
Register now!
Learn how use the CAT functions in SAS to join values from multiple variables into a single value.
Find more tutorials on the SAS Users YouTube channel.
Ready to level-up your skills? Choose your own adventure.