BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
MAC1430
Pyrite | Level 9

Hi everyone,

MAC1430_1-1632817895978.png

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

1 ACCEPTED SOLUTION

Accepted Solutions
FreelanceReinh
Jade | Level 19

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 hUnlike 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[iin 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.)

View solution in original post

3 REPLIES 3
ballardw
Super User

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.

 

 

FreelanceReinh
Jade | Level 19

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 hUnlike 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[iin 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.)

MAC1430
Pyrite | Level 9
Thank you very much for your help Reinhard, it works well now 🙂

SAS Innovate 2025: Register Now

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!

How to Concatenate Values

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.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 3 replies
  • 734 views
  • 1 like
  • 3 in conversation