Skip to main content

Custom VuC functions: Mersenne twister-based randomizer functions

Roland Stens, Independent Consultant
Roland Stens is an independent consultant based in Vancouver, Canada, who specializes in QA and testing -- particularly performance and robustness testing. His background is in programming, system analysis, database and network management, testing, and project/test management. As an active participant in various forums related to performance testing, he shares his insights with other testers to help expand their knowledge and vision of the tools and testing processes. He is happy to answer questions by e-mail.

Summary:  These custom VuC functions generate random integers that are more perfectly random than the numbers generated by the standard VuC randomizer functions.

Date:  30 Jun 2005
Level:  Introductory
Activity:  331 views
Comments:  

Editor's note: This article is part of a library of custom VuC functions developed by performance test engineers to handle special situations encountered in scripting applications. For an overview of the library and links to other custom functions, see "A library of custom VuC functions."

The Mersenne twister-based functions generate random integers that are more perfectly random than the numbers generated by the standard VuC randomizer functions.

Purpose/use

The standard VuC rand, srand, and uniform functions are the basis of VuC randomizer functions. The algorithm used by these functions creates less than perfectly random results under certain circumstances. Research by Calvin Arnason, a Rational tools user, yielded an alternative officially called "Mersenne Twister: A 623-Dimensionally Equidistributed Uniform Pseudo-random Number Generator." This random-number generator was originally conceived by Makoto Matsumoto and Takuji Nishimura of Keio University, Yokohama, Japan. Visit the generator's home page for more details.

Since the code is made publicly available under the GNU and BSD licenses, I decided to try to make this generator work in VuC. After solving several issues with the code, I came up with a working MT-based random-number generator with a very high quality random-number output.

To use this random-number generator, you must first create the script shown below under "Function code." Copy this function script at the top of your VU script or make the function script into a .h file and include it directly after the VU.h line in your VU script.

If you copy the code into mtrandom.h in your c:\Rational\Rational Test\include directory, you can use the following include:

#include <mtrandom.h>

If you copy the code into mtrandom.h in your repository's script directory, you can use the following include:

#include "mtrandom.h"


Requirements

There are no external requirements to use these functions.


Function code

The code below includes these three functions:

  • mtrand -- An alternative to the VuC rand function that will return a random integer uniformly distributed between 0 and 32767.
  • smtrand -- The function used to "seed" the randomizer, which is mandatory; the default seed is 4357. This function differs from the VuC srand function in that it doesn't return a value.
  • mtuniform -- An alternative to the VuC uniform function that will return a random integer uniformly distributed in a specified range.
/*************************************************************************/
/* A C-program for MT19937: Integer version (1999/10/28)           */
/* gen rand() generates one pseudo random unsigned integer (32-bit)  */
/* which is uniformly distributed among 0 to 2^32-1 for each       */
/* call. sgen rand(seed) sets initial values to the working area    */
/* of 624 words. Before gen rand(), sgen rand(seed) must be          */
/* called once. (Seed is any 32-bit integer.)                      */
/*  Coded by Takuji Nishimura, considering the suggestions by      */
/* Topher Cooper and Marc Rieffel in July-Aug. 1997.               */
/*************************************************************************/
/* Adapted for use in Rational VuC by Roland Stens after a         */
/* suggestion by Calvin Arnason. Feedback on this implementation   */
/* can be sent to rstens@uniserve.com                              */
/*************************************************************************/
/* This library is free software; you can redistribute it and/or   */
/* modify it under the terms of the GNU Library General Public     */
/* License as published by the Free Software Foundation; either    */
/* version 2 of the license, or (at your option) any later         */
/* version. This library is distributed in the hope that it will   */
/* be useful, but WITHOUT ANY WARRANTY; without even the implied   */
/* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */
/* See the GNU Library General Public License for more details.    */
/* You should have received a copy of the GNU Library General      */
/* Public License along with this library; if not, write to the    */
/* Free Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA   */ 
/* 02111-1307  USA                                                 */
/*************************************************************************/
/* Copyright (C) 1997, 1999 Makoto Matsumoto and Takuji Nishimura. */
/* Any feedback is very welcome. For any question, comments,       */
/* see http://www.math.keio.ac.jp/matumoto/emt.html or email       */
/* matumoto@math.keio.ac.jp                                        */
/*************************************************************************/
/* REFERENCE                                                       */
/* M. Matsumoto and T. Nishimura,                                  */
/* "Mersenne Twister: A 623-Dimensionally Equidistributed Uniform  */
/* Pseudo- random Number Generator", ACM Transactions on Modeling   */
/* and Computer Simulation, Vol. 8, No. 1, January 1998, pp 3--3.  */
/*************************************************************************/

#include <VU.h>

/* Period parameters */  
#define N 624
#define M 397
#define MATRIX_A 0x9908b0df   /* constant vector a */
#define UPPER_MASK 0x80000000 /* most significant w-r bits */
#define LOWER_MASK 0x7fffffff /* least significant r bits */

/* Tempering parameters */   
#define TEMPERING_MASK_B 0x9d2c5680
#define TEMPERING_MASK_C 0xefc60000
#define TEMPERING_SHIFT_U(y)  (y >> 11)
#define TEMPERING_SHIFT_S(y)  (y << 7)
#define TEMPERING_SHIFT_T(y)  (y << 15)
#define TEMPERING_SHIFT_L(y)  (y >> 18)

int mt\[N\]; /* the array for the state vector */
int mti; /* mti==N+1 means mt\[N\] is not initialized */

/* Initializing the array with a seed */
proc sgen rand(seed)
   int seed; 
{
   int i;
   for (i=0;i<N;i++) {
      mt\[i\] = seed & 0xffff0000;
      seed = 69069 * seed + 1;
      mt\[i\] |= (seed & 0xffff0000) >> 16;
      seed = 69069 * seed + 1;
   }
   mti = N;
}
/***************************************************************************/
/* Initialization by "sgen rand()" is an example. Theoretically,      */
/* there are 2^19937-1 possible states as an initial state.          */
/* This function allows to choose any of 2^19937-1 ones.             */
/* Essential bits in "seed_array\[\]" are the following 19937 bits:    */
/* (seed_array\[0\]&UPPER_MASK), seed_array\[1\], ..., seed_array\[N-1\].  */
/* (seed_array\[0\]&LOWER_MASK) is discarded. Theoretically,           */
/* (seed_array\[0\]&UPPER_MASK), seed_array\[1\], ..., seed_array\[N-1\]   */
/* can take any values except all zeros.                             */
/***************************************************************************/

int func gen rand()
{
   int y;
   int mag01\[2\]={0x0, MATRIX_A};
   /* mag01\[x\] = x * MATRIX_A  for x=0,1 */

   if (mti >= N) { /* generate N words at one time */
      int kk;

      if (mti == N+1)   /* if sgen rand() has not been called, */
         sgen rand(4357); /* a default initial seed is used   */

      for (kk=0;kk<N-M;kk++) {
         y = (mt\[kk\]&UPPER_MASK)|(mt\[kk+1\]&LOWER_MASK);
         mt\[kk\] = mt\[kk+M\] ^ (y >> 1) ^ mag01\[y & 0x1\];
      }
      for (;kk<N-1;kk++) {
         y = (mt\[kk\]&UPPER_MASK)|(mt\[kk+1\]&LOWER_MASK);
         mt\[kk\] = mt\[kk+(M-N)\] ^ (y >> 1) ^ mag01\[y & 0x1\];
      }
      y = (mt\[N-1\]&UPPER_MASK)|(mt\[0\]&LOWER_MASK);
      mt\[N-1\] = mt\[M-1\] ^ (y >> 1) ^ mag01\[y & 0x1\];

      mti = 0;
   }

   y = mt\[mti++\];
   y ^= TEMPERING_SHIFT_U(y);
   y ^= TEMPERING_SHIFT_S(y) & TEMPERING_MASK_B;
   y ^= TEMPERING_SHIFT_T(y) & TEMPERING_MASK_C;
   y ^= TEMPERING_SHIFT_L(y);

   return y; 
}

/*************************************************************************/
/* "Mersenne Twister" VuC  random functions added by Roland Stens   */
/*************************************************************************/

/* Replacement for the "uniform" function                          */
int func mtuniform(start,end)
int start;
int end;
{
   return abs(gen rand() % (end-start+1)) + start;
}

/* Replacement for the " rand" function                             */
int func mt rand()
{
   return abs(gen rand() % 32768);
}

/* The seed function                                               */
proc smt rand(seed)
int seed;
{
   sgen rand(seed);
}
/*************************************************************************/
/*************************************************************************/

As mentioned earlier, this code can be placed in each calling script immediately following the #include command, or it can go in a separate .h file referenced by an additional #include command. These functions can then be put in either the test script section of the repository or the Rational Test include directory. Putting them in the latter location will give you the benefit of not having to copy the functions into every repository you work with.


Command syntax

int mtuniform( min-value, max-value)

where min-value is the minimum random integer to be returned and max-value is the maximum random integer to be returned.

int mtrand()
smtrand (seed)

where seed is the non-negative integer used to seed the random-number generator. This seed procedure always needs to be called once before you use the mtrand or the mtuniform functions.


Examples of Use

Using the functions as shown in the following example will create 500 random numbers from 1 to 1000:

smtrand(4357);
for (i=0; i<500; i++) 
{
   printf("%d\n", mtuniform(1,1000));
}

These random numbers could be employed, for instance, to spread the start of a large group of virtual users. You would implement the following code if, say, the requirement were that every user has to wait at least 2 seconds but has to proceed after a maximum of 30 seconds:

smtrand(_uid * 100);
  /* Set Delay Time for each user to start at different random time. */

  delay(mtuniform(_uid * 2000,_uid * 30000));
  
  /* End Set Delay Time. */
  


About the author

Roland Stens is an independent consultant based in Vancouver, Canada, who specializes in QA and testing -- particularly performance and robustness testing. His background is in programming, system analysis, database and network management, testing, and project/test management. As an active participant in various forums related to performance testing, he shares his insights with other testers to help expand their knowledge and vision of the tools and testing processes. He is happy to answer questions by e-mail.

Comments



Trademarks  |  My developerWorks terms and conditions

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Rational
ArticleID=4301
ArticleTitle=Custom VuC functions: Mersenne twister-based randomizer functions
publish-date=06302005
author1-email=rstens@shaw.ca
author1-email-cc=

My developerWorks community

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere).

My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Rate a product. Write a review.

Special offers