So I have the following code:
%let n_periods=5;
data table1;
input start : MMDDYY10. end : MMDDYY10. c_date : MMDDYY10.;
format start end c_date MMDDYY10.;
datalines;
1/1/2016 12/31/2016 12/31/2016
7/1/2016 6/30/2017 12/31/2016
7/1/2015 6/30/2016 12/31/2016
7/1/2015 6/30/2018 12/31/2016
7/1/2013 6/30/2023 12/31/2016
9/1/2010 10/31/2020 12/31/2016
7/1/2017 6/30/2018 12/31/2016
3/1/2008 2/28/2009 12/31/2016
1/1/2013 12/31/2013 12/31/2016
9/1/2011 10/31/2012 12/31/2016
;
run;
data periods (drop=_i);
set table1;
array per[&n_periods.];
do _i = 1 to &n_periods.;
per[_i] = c_date-365*_i;
end;
run;
proc iml;
start factor_dev(start_dt,end_dt,c_date);
accrued=c_date-start_dt;
duration=end_dt-start_dt;
if accrued/duration>1 then do ;
factor_dev=1;
end;
else if accrued/duration<0 then do;
factor_dev=0;
end;
else if accrued/duration then do;
factor_dev=accrued/duration;
end;
return (factor_dev);
finish;
periods=j(10,3,0);
use periods;
read all var _all_ into periods;
close periods;
factor_dev_acu=j(dimension(periods)[1,1],&n_periods.,0);
print periods;
do i=1 to dimension(periods)[1,1];
do j=1 to &n_periods.;
factor_dev_acu[i,j]=factor_dev(periods[i,1],periods[i,2],periods[i,j+2]);
end;
end;
print factor_dev_acu;
When I run it, I get the "ERROR: (execution) Matrix has not been set to a value." error.
The problem appears to be in line 64. I can't find the reason why it's not accepting the third parameter, if I change it to
periods[i,3]
The program executes without errors, but I can't seem to be able to use anything other than number constants.
Any idea on what I'm doing wrong?
Logic error here:
else if accrued/duration then do;
This executes if accrued/duration is exactly equal to one, otherwise no value is returned, hence the error you are seeing.
The proper code is
else do;
Logic error here:
else if accrued/duration then do;
This executes if accrued/duration is exactly equal to one, otherwise no value is returned, hence the error you are seeing.
The proper code is
else do;
In your IF-THEN/ELSE statements., you have handled the cases where ACCRUED is nonzero, but the error is occuring when ACCRUED=0. Define a result for that situation.
...
else if accrued/duration then do; /* handles all nonzero in (0,1) */
factor_dev=accrued/duration;
end;
else
factor_dev = THE_RESULT_WHEN_accrued_IS_ZERO;
@Rick_SAS wrote:
In your IF-THEN/ELSE statements., you have handled the cases where ACCRUED is nonzero, but the error is occuring when ACCRUED=0. Define a result for that situation.
... else if accrued/duration then do; /* handles all nonzero in (0,1) */ factor_dev=accrued/duration; end; else factor_dev = THE_RESULT_WHEN_accrued_IS_ZERO;
I don't see a reason to use "if accrued/duration" in this IF/THEN logic flow. It just complicates things. A simple "else do;" will work here, because cases where the ratio is <0 and the ratio is >1 are previously covered.
Hi Paige. No, that logic is not correct. The OP's last ELSE IF statement evaluates to TRUE whenever the condition is nonzero, but none of the cases cover the situation when the expression is exactly zero.
You don't need to use IML to see this. IF-THEN/ELSE statements are the same throughout SAS, including the DATA step:
data Want;
input accrdur @@;
if accrdur>1 then do ;
factor_dev=1;
end;
else if accrdur<0 then do;
factor_dev=2;
end;
else if accrdur then do; /* TRUE when nonzero */
factor_dev=3;
end;
else /* handle zero */
factor_dev=4;
datalines;
2 -2 0.5 0
;
proc print; run;
So, if I add an else-do, the case where the expression evaluates to zero are covered.
Seems to me both of you are right , and I get a bad mark for faulty logic
Save $250 on SAS Innovate and get a free advance copy of the new SAS For Dummies book! Use the code "SASforDummies" to register. Don't miss out, May 6-9, in Orlando, Florida.