fsultra.c

Go to the documentation of this file.
00001 /* 
00002 FSU - ULTRA     The greatest random number generator that ever was
00003                 or ever will be.  Way beyond Super-Duper.
00004                 (Just kidding, but we think its a good one.)
00005 
00006 Authors:        Arif Zaman (arif@stat.fsu.edu) and
00007                 George Marsaglia (geo@stat.fsu.edu).
00008 
00009 Date:           27 May 1992
00010 
00011 Version:        1.05
00012 
00013 Copyright:      To obtain permission to incorporate this program into
00014                 any commercial product, please contact the authors at
00015                 the e-mail address given above or at
00016 
00017                 Department of Statistics and
00018                 Supercomputer Computations Research Institute
00019                 Florida State University
00020                 Tallahassee, FL 32306.
00021 
00022 See Also:       README          for a brief description
00023                 ULTRA.DOC       for a detailed description
00024 
00025 -----------------------------------------------------------------------
00026 */ 
00027 /*
00028    File: ULTRA.C
00029 
00030    This is the ULTRA random number generator written entirely in C.
00031 
00032    This may serve as a model for an assembler version of this routine.
00033    The programmer should avoid simply duplicating and instead use the
00034    usual assembler features to increase the speed of this routine.
00035 
00036    Especially the subroutine SWB should be replaced by the one
00037    machine instruction (usually called subtract-with-borrow) that
00038    is available in almost every hardware.
00039 
00040    For people not familiar with 8086 assembler, it may help to
00041    consult this when reading the assembler code. This program should
00042    be a dropin replacement for the assembler versions, but is about
00043    half as fast.
00044 */
00045 
00046 /* Slight modifications by Bruno Pincon (4 december 2004) for inclusion 
00047    in scilab and nsp:
00048 
00049    1/ in scilab we use only i32bit output ( renamed here fsultra )
00050       and  I have deleted the others;
00051 
00052    2/ only one array is now used (swbseed which is renamed
00053       swb_state) and the xor with the linear congruential generator
00054       is done only just before the output.
00055 
00056    3/ add a var is_init (to say if the generator is initialised)
00057 
00058    4/ add routine to set/get the state
00059 
00060 */
00061 #include <math.h>             /* to use floor    */
00062 #include "others_generators.h"
00063 #include "machine.h" 
00064 #include "sciprint.h"
00065 
00066 #define N  37           /* size of table        */
00067 #define N2 24           /* The shorter lag      */
00068 
00069 static int is_init=0;  
00070 static long swb_state[N];          /* state of the swb generator */
00071 static int swb_index=N;            /* an index on the swb state */
00072 static int swb_flag;               /* the carry flag for the SWB generator */
00073 static unsigned long cong_state;   /* state of the congruential generator */
00074 
00075 /* for this generator the state seems completly defined by:
00076       swb_state, swb_index, swb_flag (which define the state of the swb generator)
00077       cong_state (which defines the state of the congruential generator)
00078 */
00079 
00080 /* those are the default for the simple initialisation routine */
00081 static  double DEFAULT_SEED1= 1234567.0, DEFAULT_SEED2=7654321.0; 
00082 
00083 
00084 
00085 
00086 /* SWB is the subtract-with-borrow operation which should be one line
00087    in assembler code. This should be done by using the hardware s-w-b
00088    operation in the SWBfill routine (renamed advance_state_swb here).
00089 
00090    What has been done here is to look at the msb of x, y and z=x-y-c.
00091    Using these three bits, one can determine if a borrow bit is needed
00092    or not according to the following table:
00093 
00094         msbz=0  msby=0  msby=1          msbz=1  msby=0  msby=1
00095 
00096         msbx=0  0       1               msbx=0  1       1
00097         msbx=1  0       0               msbx=1  0       1
00098 
00099    PS: note that the definition is very carefully written because the
00100    calls to SWB have y and z as the same memory location, so y must
00101    be tested before z is assigned a value.
00102 */
00103 #define SWB(c,x,y,z) c = (y<0) ? (((z=x-y-c) < 0) || (x>=0)) : (((z=x-y-c) < 0) && (x>=0));
00104 
00105 extern void sciprint __PARAMS((char *fmt,...));
00106 
00107 void advance_state_swb()
00108 { 
00109   int i;
00110   /*
00111    *  The following are the heart of the system and should be
00112    *  written is assembler to be as fast as possible. It may even make sense
00113    *  to unravel the loop and simply wirte 37 consecutive SWB operations!
00114    */
00115   for (i=0;  i<N2; i++) 
00116     SWB(swb_flag,swb_state[i+N-N2],swb_state[i],swb_state[i]);
00117   for (i=N2; i<N;  i++) 
00118     SWB(swb_flag,swb_state[i  -N2],swb_state[i],swb_state[i]);
00119   swb_index = 0;
00120 }
00121 
00122 /* set_state_fsultra_simple initializes the state from 2 integers  
00123    
00124    it defines the constants and fills the swb_state array one bit at
00125    a time by taking the leading bit of the xor of a shift register
00126    and a congruential sequence. The same congruential generator continues
00127    to be used as a mixing generator for the Subtract-with-borrow generator
00128    to produce the `ultra' random numbers
00129 
00130    Since this is called just once, speed doesn't matter much and it might
00131    be fine to leave this subroutine coded just as it is.
00132 
00133    PS:  there are quick and easy ways to fill this, but since random number
00134         generators are really "randomness amplifiers", it is important to
00135         start off on the right foot. This is why we take such care here.
00136 */
00137 
00138 int set_state_fsultra_simple(double s1, double s2)
00139 { 
00140   unsigned long shrgx, tidbits=0;
00141   int i, j;
00142 
00143   if (    (s1 == floor(s1) && 0.0 <= s1 && s1 <= 4294967295.0)
00144        && (s2 == floor(s2) && 0.0 <= s2 && s2 <= 4294967295.0) )
00145     {
00146       cong_state = ((unsigned long) s1)*2 + 1;
00147       shrgx = (unsigned long) s2;
00148       for ( i=0 ; i<N ; i++)
00149         {
00150           for ( j=32 ; j>0 ; j--)
00151             { 
00152               cong_state = cong_state * 69069;
00153               shrgx = shrgx ^ (shrgx >> 15);
00154               shrgx = shrgx ^ (shrgx << 17);
00155               tidbits = (tidbits>>1) | (0x80000000 & (cong_state^shrgx));
00156             }
00157           swb_state[i] = tidbits;
00158         }
00159       swb_index = 0;
00160       swb_flag = 0;
00161       advance_state_swb();  /* pour retrouver la même séquence que ds scilab V3.0 */
00162       is_init = 1;
00163       return 1;
00164     }
00165   else
00166     {
00167       sciprint("\n\r bad seed for fsultra, must be integers in [0, 2^32-1] \n\r");
00168       return 0;
00169     }
00170 }
00171 
00172 int set_state_fsultra(double *s)
00173 { 
00174   double try;
00175   int i;
00176 
00177   try = s[0];
00178   if ( floor(try) != try || try < 0.0  ||  try > (double) N)
00179     {
00180       sciprint("\n\r the first component of the fsultra state, must be an integer in [0, %d] \n\r",N);
00181       return 0;
00182     }
00183   swb_index = (int) try;
00184 
00185   try = s[1];
00186   if ( try != 0.0  &&  try != 1.0)
00187     {
00188       sciprint("\n\r the second component of the fsultra state, must be 0 or 1 \n\r");
00189       return 0;
00190     }
00191   swb_flag = (int) try;
00192 
00193   try = s[2];
00194   if ( floor(try) != try  ||  try <= 0 ||  try > 4294967295.0 )
00195     {
00196       sciprint("\n\r the third component of the fsultra state, must be an integer in [1, 2^32-1] \n\r");
00197       return 0;
00198     }
00199   cong_state = (unsigned long) try;
00200  
00201   /* no verif here ... */
00202   for (i = 0 ; i < N ; i++) 
00203     swb_state[i] = (long) (((unsigned long) s[i+3]) & 0xffffffff);
00204 
00205   is_init = 1;
00206   return 1;
00207 }
00208 
00209 
00210 /*  to return the state at the scilab level  */
00211 void get_state_fsultra(double s[])
00212 {
00213   int i;
00214 
00215   if ( ! is_init )
00216     set_state_fsultra_simple(DEFAULT_SEED1, DEFAULT_SEED2);
00217 
00218   s[0] = (double)  swb_index;
00219   s[1] = (double)  swb_flag;
00220   s[2] = (double)  cong_state;
00221   for (i = 0 ; i < N ; i++) 
00222     s[i+3] = (double) (unsigned long) swb_state[i];
00223 }
00224 
00225 unsigned long fsultra()
00226 {
00227   if (swb_index >= N)  /* generate N words at one time */
00228     { 
00229       if ( ! is_init )
00230         set_state_fsultra_simple(DEFAULT_SEED1, DEFAULT_SEED2);
00231       else
00232         advance_state_swb();
00233     }
00234   return (swb_state[swb_index++] ^ (cong_state = cong_state * 69069));
00235 }

Generated on Sun Mar 4 15:03:59 2007 for Scilab [trunk] by  doxygen 1.5.1