IBM Mainframe Forum Index
 
Log In
 
IBM Mainframe Forum Index Mainframe: Search IBM Mainframe Forum: FAQ Register
 

SAS - How to generate a random number between 1 and n


IBM Mainframe Forums -> All Other Mainframe Topics
Post new topic   Reply to topic
View previous topic :: View next topic  
Author Message
dick scherrer

Moderator Emeritus


Joined: 23 Nov 2006
Posts: 19243
Location: Inside the Matrix

PostPosted: Tue Sep 11, 2012 9:15 am
Reply with quote

Howdy,

Ya never know what will come thru the door . . . icon_wink.gif

One of the programming groups asked if i knew how to do this using SAS - i don't.

They need to pull a sample from a universe of several million entries. The rules they are to follow (specified by those who receive the sample) is that they are to generate a random number between 1 and n and once they have this initial number, they are to read the data and extract every nth entry.

The Rules document mentions SAS several places and that team lead would like to use it for brownie points.

I can count on less than 1 hand the "things" i've done with SAS and these were clones of something that was already running. Went to the SAS site and their "hits" are more comprehensive than i need. Our forum has over 500 SAS topics, but only 2 contain "random" . . .

What i'd like to do is run a SAS process that takes in a parm or sysin specifying 'n' and "writes" the random number.

Thanks,

d
Back to top
View user's profile Send private message
Bill O'Boyle

CICS Moderator


Joined: 14 Jan 2008
Posts: 2501
Location: Atlanta, Georgia, USA

PostPosted: Tue Sep 11, 2012 9:47 am
Reply with quote

Dick,

I Googled "SAS Random Number Generator Function" and got several hits, one example using the SAS "RAND" function.

HTH....
Back to top
View user's profile Send private message
Robert Sample

Global Moderator


Joined: 06 Jun 2008
Posts: 8700
Location: Dubuque, Iowa, USA

PostPosted: Tue Sep 11, 2012 5:13 pm
Reply with quote

Code:
//STEP1 EXEC SAS,PARM='SYSPARM=<value>'
//RANOUT DD DISP=SHR,DSN=....
//SYSIN DD *
DATA _NULL_;
     SEED = SUBSTR("&SYSPARM",1)+0 ;
     RANVAL = INT(RANUNI(SEED)*N) + 1 ;
     FILE RANOUT;
     PUT RANVAL ;
This code is not tested but other than possible syntax issues it should meet the need. RANUNI returns a uniform random number between 0 and 1. To scale a random number between 0 and 1 to the range M to N, multiply the random number by N, take the integer value of that (which gives a range of 0 to N) and add M to result so the range becomes M to M+N.
Back to top
View user's profile Send private message
dick scherrer

Moderator Emeritus


Joined: 23 Nov 2006
Posts: 19243
Location: Inside the Matrix

PostPosted: Tue Sep 11, 2012 6:36 pm
Reply with quote

Thanks guys,

@Bill - yup, found those and several others that left me thinking Whoa all i wanted was one leetle number icon_smile.gif

@Robert - ran the code you posted and this is what was returned:
Code:
                                                           The SAS System
44444444444444444444444444444444444444444444444444444444444E884ECE4EAAA89
0000000000000000000000000000000000000000000000000000000000038502120282354
_________________________________________________________________________
.                                                                       
4444444444444444444444444444444444444444444444444444444444444444444444444
B000000000000000000000000000000000000000000000000000000000000000000000000


Multiple runs give the x'4B'. . .

Thanks,

d
Back to top
View user's profile Send private message
Robert Sample

Global Moderator


Joined: 06 Jun 2008
Posts: 8700
Location: Dubuque, Iowa, USA

PostPosted: Tue Sep 11, 2012 6:43 pm
Reply with quote

The dot means the value is missing. You need to substitute N in the code with whatever your maximum value is. If you did that, add
Code:
PUT _ALL_ ;
before the FILE RANOUT; statement so I can see which SAS variable is not defined. That will list all the values in the DATA step on your SAS log.
Back to top
View user's profile Send private message
dick scherrer

Moderator Emeritus


Joined: 23 Nov 2006
Posts: 19243
Location: Inside the Matrix

PostPosted: Tue Sep 11, 2012 7:01 pm
Reply with quote

Hi Robert,

Added the _ALL_ and now i get:
Code:
                                                           The SAS System
44444444444444444444444444444444444444444444444444444444444E884ECE4EAAA89
0000000000000000000000000000000000000000000000000000000000038502120282354
_________________________________________________________________________
.                                                                       
4444444444444444444444444444444444444444444444444444444444444444444444444
B000000000000000000000000000000000000000000000000000000000000000000000000
_________________________________________________________________________
SEED=55 RANVAL=. N=. _ERROR_=0 _N_=1                                     
ECCC7FF4DCDECD744D7446CDDDD67F46D67F4444444444444444444444444444444444444
2554E550915513EB05EB0D59969DE00D5DE10000000000000000000000000000000000000


I used 55 for the "seed" value.
Back to top
View user's profile Send private message
Robert Sample

Global Moderator


Joined: 06 Jun 2008
Posts: 8700
Location: Dubuque, Iowa, USA

PostPosted: Tue Sep 11, 2012 8:07 pm
Reply with quote

If you want random numbers in the range 1 to 20, change
Code:
     RANVAL = INT(RANUNI(SEED)*N) + 1 ;
to
Code:
     RANVAL = INT(RANUNI(SEED)*20) + 1 ;
or you could add
Code:
N = 20 ;
before this statement.
Back to top
View user's profile Send private message
dick scherrer

Moderator Emeritus


Joined: 23 Nov 2006
Posts: 19243
Location: Inside the Matrix

PostPosted: Tue Sep 11, 2012 9:30 pm
Reply with quote

Hi Robert,

Here's what did the deed:
Code:
//SASPROC  EXEC PROC=SAS,                   
//         PARM.SAS='SYSPARM=200'           
//RANOUT   DD SYSOUT=*                     
//SAS.SYSIN DD *                           
DATA _NULL_;                               
     SEED = SUBSTR("&SYSPARM",1)+0 ;       
     RANVAL = INT(RANUNI(SEED)*209) + 1 ;   
     FILE RANOUT;                           
     PUT RANVAL ;                           
     PUT _ALL_  ;                           
//                                         


'Preciate it icon_smile.gif

Just anticipatin' . . . What if they want the random number to change even if they specify the same seed? As it is now (which is what i expected) running the same seed multpile times returns the same random number.

d
Back to top
View user's profile Send private message
Robert Sample

Global Moderator


Joined: 06 Jun 2008
Posts: 8700
Location: Dubuque, Iowa, USA

PostPosted: Tue Sep 11, 2012 10:02 pm
Reply with quote

Quote:
What if they want the random number to change even if they specify the same seed?
The whole point of the seed is that the random number sequence won't change unless the seed changes. I would accomplish what you are saying by doing something like
Code:
SEED = INT(MOD (TIME(), SEED)) ;
as the line before RANVAL=. This will cause the seed value to be dependent upon the time of day as well as the parameter, so you will get different random numbers even though the parameter is not changed.
Back to top
View user's profile Send private message
vasanthz

Global Moderator


Joined: 28 Aug 2007
Posts: 1744
Location: Tirupur, India

PostPosted: Tue Sep 11, 2012 11:30 pm
Reply with quote

Hi,
Here is a code similar to Robert's idea using 0 as seed,
When we use 0 as seed, the RANUNI function automatically takes time as the seed and generated random numbers which are truly random.
Code:
%let sysparm = 20; /* When this parameter is passed via JCL, remove this line. */
data wells;
RANVAL=ceil(ranuni(0)*&sysparm) ;
/* FILE RANOUT; */
put RANVAL;
run;


Output when the above program was run in a loop for 20 times:
Code:
16
7
8
12
9
13
16
14
8
18
2
16
4
14
3
13
9
13
4
8



Hope it helps,
Back to top
View user's profile Send private message
dick scherrer

Moderator Emeritus


Joined: 23 Nov 2006
Posts: 19243
Location: Inside the Matrix

PostPosted: Wed Sep 12, 2012 1:31 am
Reply with quote

Hi Guys,

@Robert
made a slight mod to latest SEED=
Code:
   SEED = INT(MOD (TIME(), SUBSTR("&SYSPARM",1)+0)) ;

When i used the posted line, i was back to the x'4B'. With the mod, it appears to work as advertised icon_cool.gif

@Vasanth
Copied in your code as:
Code:
DATA WELLS;                                     
     RANVAL=CEIL(RANUNI(0)*&SYSPARM) ;         
     FILE RANOUT; */                           
     PUT RANVAL;                               
     PUT _ALL_  ;                               
This also generates different random numbers from the same parm.

I'll talk with the people with this "opportunity" and explain they are welcome to both the "same value" code or the "different each run code".

Thanks to you both!

When the scope "creeps" i may be back icon_wink.gif

d
Back to top
View user's profile Send private message
dick scherrer

Moderator Emeritus


Joined: 23 Nov 2006
Posts: 19243
Location: Inside the Matrix

PostPosted: Thu Nov 01, 2012 12:22 am
Reply with quote

Yup, scope has creeped and i'm looking for what (i hope) is a very trivial bit of info.

First, thanks again for all of the help earlier. 'Tis working just as was desired.

However, now the requirement has changed a bit and instead of using sysparm, the value needs to be read from a data file and used in the same way "sysparm" was used originally. Suggestions?

Also, i've been to the SAS site and they sure do have the documentation available - an overwhelming amount. With my extremely limited SAS exposure, i have/had no idea which 1 or few manuals might be good for a SAS beginner (me).

Is there a for-pay book that anyone might recommend? Looks like i'd best prepare for more of these . . . icon_cool.gif

d
Back to top
View user's profile Send private message
Robert Sample

Global Moderator


Joined: 06 Jun 2008
Posts: 8700
Location: Dubuque, Iowa, USA

PostPosted: Thu Nov 01, 2012 12:30 am
Reply with quote

Look for The Little SAS Book: A Primer which is a good starting point, albeit a pricy starting point. There's a SAS for Dummies book on Amazon but I haven't looked at it so I'm not sure how good it is.
Back to top
View user's profile Send private message
dick scherrer

Moderator Emeritus


Joined: 23 Nov 2006
Posts: 19243
Location: Inside the Matrix

PostPosted: Thu Nov 01, 2012 12:38 am
Reply with quote

Thanks Robert,

The Amazon price is now below $40.

Any suggestion on how to use a value from an input file instead of sysparm?

d
Back to top
View user's profile Send private message
Robert Sample

Global Moderator


Joined: 06 Jun 2008
Posts: 8700
Location: Dubuque, Iowa, USA

PostPosted: Thu Nov 01, 2012 12:38 am
Reply with quote

Code:
DATA WELLS;                                     
     INFILE SEEDFILE ;
     INPUT SEEDVAL ;
     RANVAL=CEIL(RANUNI(0)*SEEDVAL) ;         
     FILE RANOUT; */                           
     PUT RANVAL;                               
     PUT _ALL_
will work as long as SEEDVAL is something SAS can recognize as a number. JCL would be (using 12345 for the seed)
Code:
//SEEDFILE DD *
12345
/*
although SEEDFILE could point to a file, too.
Back to top
View user's profile Send private message
vasanthz

Global Moderator


Joined: 28 Aug 2007
Posts: 1744
Location: Tirupur, India

PostPosted: Thu Nov 01, 2012 12:53 am
Reply with quote

Hi D,
"Little SAS book" is one of the good SAS tutorials.
I have the "SAS for Dummies" (black and yellow cover with a cartoon guy's face in front) but the book keeps beating around the bush and does not really gets into serious programming whatsoever, lengthy as well.

I have attached one of the PDF(50 actual pages & available free) after which little SAS book can be more useful.
.
The PDF would say "Advanced SAS tutorial" but trust me, its very basic and interesting with examples. It has some information relating to PC SAS, but PC sas and mainframe SAS are the same in terms of program.

Many of my collegues have found it very useful for beginning. Hope it helps some more people.
Back to top
View user's profile Send private message
dick scherrer

Moderator Emeritus


Joined: 23 Nov 2006
Posts: 19243
Location: Inside the Matrix

PostPosted: Thu Nov 01, 2012 1:16 am
Reply with quote

Thanks again!

Worked like a charm! Both with a dd * and an actual dsn.

Later,

d
Back to top
View user's profile Send private message
dick scherrer

Moderator Emeritus


Joined: 23 Nov 2006
Posts: 19243
Location: Inside the Matrix

PostPosted: Thu Nov 01, 2012 1:18 am
Reply with quote

Thanks Vasanth,

I've downloaded the pdf and will check it out.

d
Back to top
View user's profile Send private message
Robert Sample

Global Moderator


Joined: 06 Jun 2008
Posts: 8700
Location: Dubuque, Iowa, USA

PostPosted: Thu Nov 01, 2012 1:20 am
Reply with quote

Great -- glad to hear it worked. icon_smile.gif
Back to top
View user's profile Send private message
dick scherrer

Moderator Emeritus


Joined: 23 Nov 2006
Posts: 19243
Location: Inside the Matrix

PostPosted: Fri Nov 02, 2012 7:06 pm
Reply with quote

Heee's Baaaack . . . .

One (hopefully) last "opportunity" on this (Ha).

My "users" stopped by yesterday and 'splained that what they would really like is the ability to process multiples. I spent time last night looking thru our posts and the internet and did not find an example of SAS code that read an qsam file (with multiple fields).

I seem to recall that at least one of our topics had a SAS external file definition that had individual fields, but i was unable to find it.

Over the weekend, i'll order "the little sas book" and download some more "stuff".

d
Back to top
View user's profile Send private message
Robert Sample

Global Moderator


Joined: 06 Jun 2008
Posts: 8700
Location: Dubuque, Iowa, USA

PostPosted: Fri Nov 02, 2012 7:50 pm
Reply with quote

If you put multiple values in SEEDFILE in the last code I posted, SAS will read each one and generate a random number. Do you need to be able to write each of these random numbers to an output file as well?
Back to top
View user's profile Send private message
dick scherrer

Moderator Emeritus


Joined: 23 Nov 2006
Posts: 19243
Location: Inside the Matrix

PostPosted: Fri Nov 02, 2012 8:45 pm
Reply with quote

My bad icon_redface.gif
Yup, i've successfully run multiple input records.

However, I need to break out fields on the same input record(s). The value(s) will not always be in position 1.

So far, i've been able to find/use a numeric value that is not in position 1 (@nnn).

Also needed is a way to generate the random number without the leading zeros suppressed icon_confused.gif

'Preciate it!

d
Back to top
View user's profile Send private message
Robert Sample

Global Moderator


Joined: 06 Jun 2008
Posts: 8700
Location: Dubuque, Iowa, USA

PostPosted: Fri Nov 02, 2012 9:29 pm
Reply with quote

Using a trailing @@ on the INPUT line such as
Code:
     INPUT SEEDVAL  @@ ;
will cause SAS to start looking for the second value immediately after the end of the first value. Make sure you do NOT have line numbers in your file, though, or the line numbers will be read as data.

Using a Zn. format for the PUT statement will cause SAS to add leading zeroes. If you want the value to be 8 digits wide, for example, use
Code:
PUT RANVAL Z8. ;
Back to top
View user's profile Send private message
dick scherrer

Moderator Emeritus


Joined: 23 Nov 2006
Posts: 19243
Location: Inside the Matrix

PostPosted: Fri Nov 02, 2012 10:24 pm
Reply with quote

Excellent - the Zn. did the trick!

Once again, thanks very much.

d
Back to top
View user's profile Send private message
Charles Wolters

New User


Joined: 30 Mar 2011
Posts: 48
Location: United States

PostPosted: Thu Nov 15, 2012 1:33 am
Reply with quote

Dick,

I have used the following approach where BOUND is your N value so here I want to select a random number between 1 and 25. Using the PARM keyword I am feeding the value of BOUND to SAS. The RANUNI function activates the SAS random number generator. The value of 959078 is the seed I have given to random number generator and this is arbitrary. The random number is written to the SAS log and I am not sure this is where you want it.

Charles Wolters

//S688CLWX JOB XXXUNKA9,S688CLW,
// MSGCLASS=R,NOTIFY=&SYSUID
// SET BOUND=25
//STEP1 EXEC SAS,PARM='SYSPARM="&BOUND"'
//SYSIN DD *
***PASS INTERVAL FOR RANDOM NUMBER GENERATION ;
DATA _NULL_ ;
RANNUM = INT(&SYSPARM * RANUNI(959078)) + 1 ;
CALL SYMPUT('MYNUM',PUT(RANNUM,8.)) ;
RUN ;
%PUT SELECTED RANDOM NUMBER = &MYNUM ;
Back to top
View user's profile Send private message
View previous topic :: :: View next topic  
Post new topic   Reply to topic View Bookmarks
All times are GMT + 6 Hours
Forum Index -> All Other Mainframe Topics Goto page 1, 2  Next

 


Similar Topics
Topic Forum Replies
No new posts XML Generate issue COBOL Programming 0
No new posts Pulling a fixed number of records fro... DB2 2
No new posts Substring number between 2 characters... DFSORT/ICETOOL 2
No new posts Generate random number from range of ... COBOL Programming 3
No new posts Increase the number of columns in the... IBM Tools 3
Search our Forums:

Back to Top