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.
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"
There are no external requirements to use these functions.
The code below includes these three functions:
-
mtrand-- An alternative to the VuCrandfunction 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 VuCsrandfunction in that it doesn't return a value. -
mtuniform-- An alternative to the VuCuniformfunction 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.
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.
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. */ |
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.





