An Idea Exchange for SAS software and services

by Super User
on ‎01-26-2017 03:54 AM

Support this, but this must be easy to implement using FCMP?

by Super User
on ‎01-26-2017 06:55 AM

Could you provide an example of where you would use such a function.  Am not against it, but just don't see where to use it.  If its datastep:

data have;
data want;
  set have (rename=(a=b b=a));
by Respected Advisor
on ‎01-26-2017 08:32 AM

ChrisNZ wrote:

Just a simple function to replace



A  =B;

B  =TMP;


with shorter and more legible


call swap(A,B);


and RC=swap(A,B); for macro use.



It sort of already exists.


27         data _null_;
28            input a b ;
29            put 'NOTE: Original ' (_all_)(=);
30            call allperm(2,a,b);
31            put 'NOTE: Swap     ' (_all_)(=);
32            call allperm(2,a,b);
33            put 'NOTE: Back     ' (_all_)(=);
34            cards;

NOTE: Original a=123 b=4565
NOTE: Swap     a=4565 b=123
NOTE: Back     a=123 b=4565
NOTE: Original a=8888 b=999
NOTE: Swap     a=999 b=8888
NOTE: Back     a=8888 b=999
by Community Manager
on ‎01-26-2017 12:35 PM

I checked with internal experts (okay, just one: Rick Langston) and he says that the overhead of a CALL routine would be less efficient than a macro for something like a "swap" operation.  That is, from a performance standpoint, you're better off with:


%macro swap(x,y); 
  temp = &x; 
  &y = temp; 

by Respected Advisor
‎01-26-2017 02:09 PM - edited ‎01-26-2017 02:11 PM

A test.  ALLPERM does check that a and b are the same type and length.


26         data _null_;
27            input a b;
28            do _n_ = 1 to 1e8;
29               call allperm(2,a,b);
30               end;
31            cards;

NOTE: DATA statement used (Total process time):
      real time           6.99 seconds
      cpu time            6.97 seconds
34         ;;;;

35            run;
37         %macro swap(x,y);
38           temp = &x;
39           &x=&y;
40           &y = temp;
41         %mend;
42         data _null_;
43            input a b;
44            do _n_ = 1 to 1e8;
45               %swap(a,b);
MPRINT(SWAP):   temp = a;
MPRINT(SWAP):   a=b;
MPRINT(SWAP):   b = temp;
46               end;
47            cards;

NOTE: DATA statement used (Total process time):
      real time           1.64 seconds
      cpu time            1.65 seconds

2 The SAS System                          09:25 Wednesday, January 25, 2017



by PROC Star
on ‎01-26-2017 05:02 PM

@RW9 Sometimes in some calculations, you need to swap two values around to keep going. That's not an everyday need, but it would be handy. A bit like the lag funtions are not used everyday, but is useful (much more so than my proposal) for some data manipulation.


@LinusH Not too sure about proc fcmp. Function SWAP would return nothing.


@data_null__ Thank you, I never used ALLPERM.
     ALLPERM does check that a and b are the same type and length.
     As far as I could see, type must be numeric and lengths don't matter.


@ChrisHemedinger Most requests here could be implemented as custom home-made functions.
 These functions must then be maintained, kept online, etc. That's why people ask for their implementation in the SAS language. As for performance (and you know how that matters to me), there can be a worthwhile trade-off for legibility.

Like when using the if functions rather than tests, or the cat functions:

data _null_;   * 17s;
  retain A B 'aaaaaaaaaaaa';
  length C $32;
  do i=1 to 1e9;
data _null_;   * 21s;
  retain A B 'aaaaaaaaaaaa';
  length C $32;
  do i=1 to 1e9;
data _null_;      * 8s;
  do I=1 to 1e9;
     if      I<10 then A=1; 
     else if I<11 then A=2; 
     else if I<12 then A=3; 
     else if I<13 then A=4; 
     else              A=5; 
data _null_;      * 32s;
  do I=1 to 1e9;
    A=ifn(I<10, 1 
     ,ifn(I<11, 2 
     ,ifn(I<12, 3 
     ,ifn(I<13, 4 
     ,          5))));

They are more expensive but still worth having.


by Respected Advisor
on ‎01-26-2017 05:11 PM

@ChrisNZ The swap variables can be character but they have to be the same length.  While a data step is running all numeric variables are length 8.


25         data _null_;
26            input (a b)(:$9. :$8.);
27            put 'NOTE: Original ' (_all_)(=);
28            call allperm(2,a,b);
29            put 'NOTE: Swap     ' (_all_)(=);
30            call allperm(2,a,b);
31            put 'NOTE: Back     ' (_all_)(=);
32            cards;

NOTE: Original a=123 b=4565
ERROR: In a call to the ALLPERM function or routine, argument 2 has length 9, but argument 3 has length 8. These arguments must 
       have the same length.
ERROR: Internal error detected in function ALLPERM.  The DATA step is terminating during the EXECUTION phase.
36         ;;;;
by PROC Star
on ‎01-26-2017 05:19 PM

@data_null__ It seems that I didn't look and test properly. Thank you.

While a data step is running all numeric variables are length 8 => fair enough. Smiley Happy

by New Contributor Otto
on ‎07-26-2017 01:33 PM

If you really want to do it without creating a temporary variable, and only want to do it to to integer values, then bitwise XOR swap is an option.


It is easy to encapsulate it in a macro so you can make single-line swaps in your data steps without having to later drop a variable.


%macro swap(x,y);
  &x = bxor(&x,&y);
  &y = bxor(&y,&x);
  &x = bxor(&x,&y);

data test;
  a = 1;
  b = 2;
  a = 12.123456789;
  b = 50.987654321;
data test2;
  set test;
  a_orig = a;
  b_orig = b;
  put a=hex.;
  put b=hex.;
  put a=hex.;
  put b=hex.;

Note that the second example of a floating point value ends up getting trucated to just the part before the decimal.  That appears to just be how sas bitwise functions work.


Nifty that you can do such a thing in SAS, as it is often used as a high-speed memory efficient swap in low level programming.  However, it is of limited utility given it appears to only work on integers.  More of a cool trick than something you would need to do in SAS very often.

Idea Statuses
Top Liked Authors