Does SYMPUT work in IML?

8

I received the following email:

Dear Dr. Wicklin,
Why doesn't SYMPUT work in IML? In the DATA step, I can say CALL SYMPUT("MyMacro", 5) but this doesn't work in IML!

Frustrated

Dear Frustrated,

The SYMPUT subroutine does work in SAS/IML software! However, the second argument to SYMPUT must be a character value.

The SYMPUT subroutine is used to store a value in a macro variable. In your example, you are creating the macro variable MyMacro, which will contain the string "5". Macro variables always contain a string—never a numeric value.

As stated in the documentation, the second argument to the SYMPUT subroutine is "a character constant, variable, or expression." So why does your call work in the DATA step? The DATA step automatically converts character values to numeric values, and vice versa! For example, the following DATA step parses and runs without errors:

data a;
x = 1 + "2"; /* convert char to numeric */
y = cos("0");
z = "B" || 4; /* convert numeric to char */
call symput("MyMacro", 5);
run;

However, if you look in the SAS log, you will see the following NOTEs:

NOTE: Character values have been converted to numeric values at the places given by:
      (Line):(Column).
      2:9   3:9
NOTE: Numeric values have been converted to character values at the places given by:
      (Line):(Column).
      4:12   5:24

The DATA step has "helped" you by converting between character and numeric expressions. Therefore, the SYMPUT call displays a NOTE, but not an error.

However, the SAS/IML language does not implicitly convert between character and numeric expressions. Instead, it supplies the NUM function and the CHAR function, which enable you to convert SAS/IML variables from one type to another. (You can also use the INPUTN and PUTN functions.) Therefore, in the SAS/IML language you should write CALL SYMPUT("MyMacro", char(5));

If you really want automatic conversion, use the SYMPUTX subroutine. If you call SYMPUTX in the DATA step, no NOTE will be written to the log when the second argument is numeric. If you call SYMPUTX in SAS/IML software, the second argument is silently converted from a numeric to character value.

Thanks for writing!

Share

About Author

Rick Wicklin

Distinguished Researcher in Computational Statistics

Rick Wicklin, PhD, is a distinguished researcher in computational statistics at SAS and is a principal developer of PROC IML and SAS/IML Studio. His areas of expertise include computational statistics, simulation, statistical graphics, and modern methods in statistical data analysis. Rick is author of the books Statistical Programming with SAS/IML Software and Simulating Data with SAS.

8 Comments

  1. Victor Estevao on

    I have a question similar to the earlier one on this blog.

    I am working in SAS IML and trying to dynamically create a format to print the values of an IML matrix. I determine the width w and the number of decimal places to display depending on the size of the largest and smallest values. I store the width and number of decimals in the scalars w and d respectively. I tried to create a macro variable for the format (w.d) of the matrix using the following code.
    call symput('matfrmt', left(trim(char(w))) || "." || left(trim(char(d))) );

    In IML, I create scalars w with value 12 and d with value 5. When I submit
    w = 12;
    d = 5;
    call symput('matfrmt', left(trim(char(w))) || "." || left(trim(char(d))) );
    %put "matfrmt=&matfrmt";

    SAS displays "matfrmt=5 "

    Why don't I see "matfrmt=12.5" ?

    • Rick Wicklin

      In the SAS/IML language, "||" means "horizontal concatenation of matrices." What you want is string concatenation, which is the "+" operator:
      call symput('matfrmt', strip(char(w)) + "." + strip(char(d)) );
      %put "matfrmt=&matfrmt";

      However, you don't need to do any of this, since the CHAR function accepts w and d as parameters. Just use the following:
      x = 1.23456789;
      s = char(x, w, d); /* applies w.d format to x */

  2. Vincent Bonnemains on

    Hi,
    I have an issue with combining proc iml, if/then and call symputx. If I run the following code :

    proc iml;

    call symputx("noif",3);
    %put &noif; /* works*/
    a=1;
    if a=1 then call symputx("withif",1);
    %put &withif; /* doesn't work */
    quit;
    %put &withif; /* woks */

    it appears that "noif" works well inside the proc iml whereas "withif" is only properly read after the quit statement. Is there a proper way to conditionally define a macro-variable inside a proc iml ?

    Thank you very much,

    Vincent.

    • Rick Wicklin

      To resolve the issue, put an ELSE after the IF-THEN statement, such as
      ELSE call symputx("withif",0);
      or
      ELSE ; /* empty ELSE */

      Because IML is an interactive language, it doesn't execute the IF-THEN statement until it encounters either an ELSE condition or an executable statement AFTER the IF-ELSE. This is standard practice in interactive languages because it resolves the "dangling else" conflict.

  3. Pingback: Create a SAS macro variable that contains a list of values

  4. Pingback: Compute a weighted mean in SAS - The DO Loop

  5. Thanks for all this!!
    I'd like to use this to dynamically produce a macro variable using the *value* of a matrix.

    So in a loop like:
    do j=1 to 5;
    /* bunch of work */
    call symputx("filetag",j);
    file "c:\jwm\out_iter_&j..txt";
    put /* whatever */
    end;

    So I'd like symput to result in "1" "2" "3" etc., but it seems instead to always result in "j". Any ideas?

    Thanks!

Leave A Reply

Back to Top