%MACRO FIND_CLOSEST_VALUE(limOrDedOption,limorDedValue);
%LET numOptions = %Sysfunc(Countw(&limOrDedOption.));
limOrDedSetFlag = 'N';
%DO curLimOrDed = 1 %TO &numOptions.;
IF limOrDedSetFlag = 'N" AND &curlimOrDed > 1 THEN DO;
lwrVal = %Scan(&limOrDedOption., &curLimOrDed. - 1);
uprVal = %Scan(&limOrDedOption., &curLimOrDed.);
IF &limOrDedValue. < uprVal THEN DO;
IF (&limOrDedValue. - lwrVal)/(uprVal - lwrVal) < 0.5 THEN &limOrDedValue = lwrVal;
ELSE &limOrDedValue = uprVal;
END;
END;
%END;
%MEND;
Receiving an error:
ERROR: A character operand was found in the %EVAL function or %IF condition where a numeric operand is required. The condition was:
prevLimOrDed
ERROR: Argument 2 to macro function %SCAN is not a number.
Error occurs on the lwrVal. uprVal is fine. It's almost as if the if condition is not met on the &curLirOrDed > 1
Any ideas?
Can we see the relevant portions of the code that you used to call this macro?
%LET numArray = 200000 300000 500000 1000000 2000000;
DATA TEST;
SET inforce;
%FIND_CLOSEST_VALUE(&numArray, testValue);
RUN;
This does not pass the VALUE of testValue variable to the macro, it passes the TEXT value "testValue";
testValue is actually a dataset column. The macro should check what the value in the testValue column is.
For example, say the value is 60, but acceptable values are 50 and 100.
The macro calculates if 60 is closer to 50 or 100, and based on that, resets the testValue to 50.
there are different Errors.
%MACRO FIND_CLOSEST_VALUE(limOrDedOption,limorDedValue);
%LET numOptions = %Sysfunc(Countw(&limOrDedOption.,%str( )));
limOrDedSetFlag = 'N';
/* probe of less or equal as the smallest value */
if &limOrDedValue. <= %Scan(&limOrDedOption., 1,%str( )) then do;
&limOrDedValue. = %Scan(&limOrDedOption., 1,%str( ));
limOrDedSetFlag = 'Y';
end;
/* probe of equal or greater as the highest value */
else if &limOrDedValue. >= %Scan(&limOrDedOption., -1,%str( )) then do;
&limOrDedValue. = %Scan(&limOrDedOption., -1,%str( ));
limOrDedSetFlag = 'Y';
end;
else do;
/* the value must be between 2 values or equal a value of the list*/
%DO curLimOrDed = 2 %TO &numOptions.;
IF limOrDedSetFlag = 'N' THEN DO;
lwrVal =%Scan(&limOrDedOption., %eval(&curLimOrDed. - 1));
uprVal =%Scan(&limOrDedOption., &curLimOrDed.);
IF (lwrval <= &limOrDedValue.) and (&limOrDedValue.) <= uprVal THEN DO;
IF (&limOrDedValue. - lwrVal) < (uprVal - &limOrDedValue.)
THEN &limOrDedValue. = lwrVal;
ELSE &limOrDedValue. = uprVal;
limOrDedSetFlag = 'Y';
END;
END;
%END;
end;
%MEND;
/* usage */
%LET
numArray = 200000 300000 500000 1000000 2000000;
optionsmprint;
DATA TEST;
testvalue1= 34000;
testvalue2= 340000;
testvalue3=3400000;
%FIND_CLOSEST_VALUE(&numArray., testValue1);
%FIND_CLOSEST_VALUE(&numArray., testValue2);
%FIND_CLOSEST_VALUE(&numArray., testValue3);
RUN;
Hi,
Have you tried:
lwrVal = %Scan(&limOrDedOption., %eval(&curLimOrDed. - 1));
If so maybe put options mlogic mprint symbolgen; on and see what the macro variables resolve to.
yes, I tried %eval and i tried put(&curLimOrDed,1.) - 1. I am receiving the exact same error =(
Well, couple of things:
- You have a typo in the macro, IF limOrDedSetFlag = 'N" AND - double quotes after the N.
- Secondly you only want to do the %do loop from 2 to numoptions, other 1 with -1 = 0 which is an invalid scan array.
Note, can't actually test this as no data provided.
So change: %DO curLimOrDed = 2 %TO &numOptions.;
For some reason cannot copy paste in this editor. I typed 'N" up, it is actually a 'N'.
As for the second comment, I have a condition to execule when &curLimOrDed = 1 and when &curLimOrDed > 1. The
%Scan(&limOrDedOption, &curLimOrDed. -1 ) executes only when :
IF limOrDedSetFlag = 'N" AND &curlimOrDed > 1 THEN DO;
Ok, another thought, what is the prevLimOrDed, mentioned in the error message, I don't see this in the macro or code. Also, have you tried putting options mlogic mprint symbolgen; on and seeing what is being generated?
The prevLimOrDed was me testing. sorry, removed it, still getting an error:
Perhaps start again, post the actual code (including call), the actual log text with the error, and if possible some test data which triggers the error. Will have a look tomorrow.
MARY9999: Do you have to use a macro for this? It can be done easily within a datastep. E.g.:
DATA TEST;
SET sashelp.class (rename=(age=testValue));
array limOrDedOption(8) _temporary_ (10.4,11.6,12.4,13.6,14.4,15.6,16.4,17.6);
do _n_=2 to dim(limOrDedOption);
if limOrDedOption(_n_) ge testValue then do;
if testValue+(limOrDedOption(_n_)-limOrDedOption(_n_-1))/2 gt limOrDedOption(_n_)
then closest=limOrDedOption(_n_);
else closest=limOrDedOption(_n_-1);
leave;
end;
else if _n_ eq dim(limOrDedOption) then closest=limOrDedOption(_n_);
end;
RUN;
Ideally yes, i have t odo this for 20 different variables.
Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 25. Read more here about why you should contribute and what is in it for you!
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.