msr.c

Go to the documentation of this file.
00001 /*                           M S R . C
00002  * BRL-CAD
00003  *
00004  * Copyright (c) 1994-2006 United States Government as represented by
00005  * the U.S. Army Research Laboratory.
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public License
00009  * as published by the Free Software Foundation; either version 2 of
00010  * the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful, but
00013  * WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Library General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this file; see the file named COPYING for more
00019  * information.
00020  */
00021 
00022 /** \addtogroup msr */
00023 /*@{*/
00024 
00025 /** @file msr.c
00026  * @brief
00027  * Minimal Standard RANdom number generator
00028  *
00029  * @par From:
00030  *      Stephen K. Park and Keith W. Miller
00031  *@n    "Random number generators: good ones are hard to find"
00032  *@n    CACM vol 31 no 10, Oct 88
00033  *
00034  *  @author
00035  *      Christopher T. Johnson - 90/04/20
00036  *
00037  * @par Source -
00038  *      The U. S. Army Research Laboratory
00039  *@n    Aberdeen Proving Ground, Maryland  21005-5068  USA
00040  */
00041 
00042 
00043 #ifndef lint
00044 static const char RCSid[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/libbn/msr.c,v 14.13 2006/09/03 15:15:16 lbutler Exp $ (ARL)";
00045 #endif
00046 
00047 #include "common.h"
00048 
00049 
00050 
00051 #include <stdio.h>
00052 #include <math.h>
00053 #include "machine.h"
00054 #include "bu.h"
00055 #include "vmath.h"
00056 #include "bn.h"
00057 
00058 /**
00059  * Note: BN_MSR_MAXTBL must be an even number.
00060  */
00061 #define BN_MSR_MAXTBL   4096    /* Size of random number tables. */
00062 
00063 
00064 /*      bn_unif_init    Initialize a random number structure.
00065  *
00066  * @par Entry
00067  *      setseed seed to use
00068  *      method  method to use to generate numbers;
00069  *
00070  * @par Exit
00071  *      returns a pointer to a bn_unif structure.
00072  *      returns 0 on error.
00073  *
00074  * @par Uses
00075  *      None.
00076  *
00077  * @par Calls
00078  *      bu_malloc
00079  *
00080  * @par Method @code
00081  *      malloc up a structure with pointers to the numbers
00082  *      get space for the integer table.
00083  *      get space for the floating table.
00084  *      set pointer counters
00085  *      set seed if one was given and setseed != 1
00086 @endcode
00087  *
00088  */
00089 #define A       16807
00090 #define M       2147483647
00091 #define DM      2147483647.0
00092 #define Q       127773          /* Q = M / A */
00093 #define R       2836            /* R = M % A */
00094 struct bn_unif *
00095 bn_unif_init(long int setseed, int method)
00096 {
00097         struct bn_unif *p;
00098         p = (struct bn_unif *) bu_malloc(sizeof(struct bn_unif),"bn_unif");
00099         p->msr_longs = (long *) bu_malloc(BN_MSR_MAXTBL*sizeof(long), "msr long table");
00100         p->msr_doubles=(double *) bu_malloc(BN_MSR_MAXTBL*sizeof(double),"msr double table");
00101         p->msr_seed = 1;
00102         p->msr_long_ptr = 0;
00103         p->msr_double_ptr = 0;
00104 
00105         if (setseed&0x7fffffff) p->msr_seed=setseed&0x7fffffff;
00106         p->magic = BN_UNIF_MAGIC;
00107         return(p);
00108 }
00109 
00110 /*      bn_unif_long_fill       fill a random number table.
00111  *
00112  * Use the msrad algorithm to fill a random number table
00113  * with values from 1 to 2^31-1.  These numbers can (and are) extracted from
00114  * the random number table via high speed macros and bn_unif_long_fill called
00115  * when the table is exauseted.
00116  *
00117  * @par Entry
00118  *      p       pointer to a bn_unif structure.
00119  *
00120  * @par Exit
00121  *      if (!p) returns 1 else returns a value between 1 and 2^31-1
00122  *
00123  * @par Calls
00124  *      None.  msran is inlined for speed reasons.
00125  *
00126  * @par Uses
00127  *      None.
00128  *
00129  * @par Method @code
00130  *      if (!p) return(1);
00131  *      if p->msr_longs != NULL
00132  *              msr_longs is reloaded with random numbers;
00133  *              msr_long_ptr is set to BN_MSR_MAXTBL
00134  *      endif
00135  *      msr_seed is updated.
00136 @endcode
00137  */
00138 long
00139 bn_unif_long_fill(struct bn_unif *p)
00140 {
00141         register long test,work_seed;
00142         register int i;
00143 
00144         /*
00145          * Gauss and uniform structures have the same format for the
00146          * first part (gauss is an extention of uniform) so that a gauss
00147          * structure can be passed to a uniform routine.  This means
00148          * that we only maintain one structure for gaussian distributions
00149          * rather than two.  It also means that the user can pull
00150          * uniform numbers from a guass structure when the user wants.
00151          */
00152         if (!p || (p->magic != BN_UNIF_MAGIC &&
00153             p->magic != BN_GAUSS_MAGIC)) {
00154                 BN_CK_UNIF(p);
00155         }
00156 
00157         work_seed = p->msr_seed;
00158 
00159         if ( p->msr_longs) {
00160                 for (i=0; i < BN_MSR_MAXTBL; i++) {
00161                         test = A*(work_seed % Q) - R*(work_seed / Q);
00162                         p->msr_longs[i] = work_seed = (test < 0) ?
00163                              test+M : test;
00164                 }
00165                 p->msr_long_ptr = BN_MSR_MAXTBL;
00166         }
00167         test = A*(work_seed % Q) - R*(work_seed / Q);
00168         p->msr_seed =  (test < 0) ? test+M : test;
00169         return(p->msr_seed);
00170 }
00171 
00172 /*      bn_unif_double_fill     fill a random number table.
00173  *
00174  * Use the msrad algorithm to fill a random number table
00175  * with values from -0.5 to 0.5.  These numbers can (and are) extracted from
00176  * the random number table via high speed macros and bn_unif_double_fill
00177  * called when the table is exauseted.
00178  *
00179  * @par Entry
00180  *      p       pointer to a bn_unif structure.
00181  *
00182  * @par Exit
00183  *      if (!p) returns 0.0 else returns a value between -0.5 and 0.5
00184  *
00185  * @par Calls
00186  *      None.  msran is inlined for speed reasons.
00187  *
00188  * @par Uses
00189  *      None.
00190  *
00191  * @par Method @code
00192  *      if (!p) return (0.0)
00193  *      if p->msr_longs != NULL
00194  *              msr_longs is reloaded with random numbers;
00195  *              msr_long_ptr is set to BN_MSR_MAXTBL
00196  *      endif
00197  *      msr_seed is updated.
00198 @endcode
00199  */
00200 double
00201 bn_unif_double_fill(struct bn_unif *p)
00202 {
00203         register long test,work_seed;
00204         register int i;
00205 
00206         /*
00207          * Gauss and uniform structures have the same format for the
00208          * first part (gauss is an extention of uniform) so that a gauss
00209          * structure can be passed to a uniform routine.  This means
00210          * that we only maintain one structure for gaussian distributions
00211          * rather than two.  It also means that the user can pull
00212          * uniform numbers from a guass structure when the user wants.
00213          */
00214         if (!p || (p->magic != BN_UNIF_MAGIC &&
00215             p->magic != BN_GAUSS_MAGIC)) {
00216                 BN_CK_UNIF(p);
00217         }
00218 
00219         work_seed = p->msr_seed;
00220 
00221         if (p->msr_doubles) {
00222                 for (i=0; i < BN_MSR_MAXTBL; i++) {
00223                         test = A*(work_seed % Q) - R*(work_seed / Q);
00224                         work_seed = (test < 0) ? test+M : test;
00225                         p->msr_doubles[i] = ( work_seed - M/2) * 1.0/DM;
00226                 }
00227                 p->msr_double_ptr = BN_MSR_MAXTBL;
00228         }
00229         test = A*(work_seed % Q) - R*(work_seed / Q);
00230         p->msr_seed = (test < 0) ? test+M : test;
00231 
00232         return((p->msr_seed - M/2) * 1.0/DM);
00233 }
00234 
00235 /*      bn_unif_free    free random number table
00236  *
00237  */
00238 void
00239 bn_unif_free(struct bn_unif *p)
00240 {
00241         bu_free(p->msr_doubles, "msr double table");
00242         bu_free(p->msr_longs, "msr long table");
00243         p->magic = 0;
00244         bu_free(p, "bn_unif");
00245 }
00246 
00247 
00248 /*      bn_gauss_init   Initialize a random number struct for gaussian
00249  *      numbers.
00250  *
00251  * @par Entry
00252  *      setseed         Seed to use.
00253  *      method          method to use to generate numbers (not used)
00254  *
00255  * @par Exit
00256  *      Returns a pointer toa bn_msr_guass structure.
00257  *      returns 0 on error.
00258  *
00259  * @par Calls
00260  *      bu_malloc
00261  *
00262  * @par Uses
00263  *      None.
00264  *
00265  * @par Method @code
00266  *      malloc up a structure
00267  *      get table space
00268  *      set seed and pointer.
00269  *      if setseed != 0 then seed = setseed
00270 @endcode
00271  */
00272 struct bn_gauss *
00273 bn_gauss_init(long int setseed, int method)
00274 {
00275         struct bn_gauss *p;
00276         p = (struct bn_gauss *) bu_malloc(sizeof(struct bn_gauss),"bn_msr_guass");
00277         p->msr_gausses=(double *) bu_malloc(BN_MSR_MAXTBL*sizeof(double),"msr guass table");
00278         p->msr_gauss_doubles=(double *) bu_malloc(BN_MSR_MAXTBL*sizeof(double),"msr guass doubles");
00279         p->msr_gauss_seed = 1;
00280         p->msr_gauss_ptr = 0;
00281         p->msr_gauss_dbl_ptr = 0;
00282 
00283         if (setseed&0x7fffffff) p->msr_gauss_seed=setseed&0x7fffffff;
00284         p->magic = BN_GAUSS_MAGIC;
00285         return(p);
00286 }
00287 
00288 /*      bn_gauss_fill   fill a random number table.
00289  *
00290  * Use the msrad algorithm to fill a random number table.
00291  * hese numbers can (and are) extracted from
00292  * the random number table via high speed macros and bn_msr_guass_fill
00293  * called when the table is exauseted.
00294  *
00295  * @par Entry
00296  *      p       pointer to a bn_msr_guass structure.
00297  *
00298  * @par Exit
00299  *      if (!p) returns 0.0 else returns a value with a mean of 0 and
00300  *          a variance of 1.0.
00301  *
00302  * @par Calls
00303  *      BN_UNIF_CIRCLE to get to uniform random number whos radius is
00304  *      <= 1.0. I.e. sqrt(v1*v1 + v2*v2) <= 1.0
00305  *      BN_UNIF_CIRCLE is a macro which can call bn_unif_double_fill.
00306  *
00307  * @par Uses
00308  *      None.
00309  *
00310  * @par Method @code
00311  *      if (!p) return (0.0)
00312  *      if p->msr_longs != NULL
00313  *              msr_longs is reloaded with random numbers;
00314  *              msr_long_ptr is set to BN_MSR_MAXTBL
00315  *      endif
00316  *      msr_seed is updated.
00317 @endcode
00318  */
00319 double
00320 bn_gauss_fill(struct bn_gauss *p)
00321 {
00322         register int i;
00323         /* register */ double v1,v2,r,fac;
00324 
00325         BN_CK_GAUSS(p);
00326 
00327         if (p->msr_gausses) {
00328                 for (i=0; i< BN_MSR_MAXTBL-1; ) {
00329                         BN_UNIF_CIRCLE((struct bn_unif *)p,v1,v2,r);
00330                         if (r<0.00001) continue;
00331                         fac = sqrt(-2.0*log(r)/r);
00332                         p->msr_gausses[i++] = v1*fac;
00333                         p->msr_gausses[i++] = v2*fac;
00334                 }
00335                 p->msr_gauss_ptr = BN_MSR_MAXTBL;
00336         }
00337 
00338         do {
00339                 BN_UNIF_CIRCLE((struct bn_unif *)p,v1,v2,r);
00340         } while (r < 0.00001);
00341         fac = sqrt(-2.0*log(r)/r);
00342         return(v1*fac);
00343 }
00344 /*      bn_gauss_free   free random number table
00345  *
00346  */
00347 void
00348 bn_gauss_free(struct bn_gauss *p)
00349 {
00350         bu_free(p->msr_gauss_doubles, "msr guass doubles");
00351         bu_free(p->msr_gausses,"msr guass table");
00352         bu_free(p,"bn_msr_guass");
00353 }
00354 
00355 
00356 #undef A
00357 #undef M
00358 #undef DM
00359 #undef Q
00360 #undef R
00361 
00362 /*@}*/
00363 /*
00364  * Local Variables:
00365  * mode: C
00366  * tab-width: 8
00367  * c-basic-offset: 4
00368  * indent-tabs-mode: t
00369  * End:
00370  * ex: shiftwidth=4 tabstop=8
00371  */

Generated on Mon Sep 18 01:24:47 2006 for BRL-CAD by  doxygen 1.4.6