core/vnl/vnl_random.cxx
Go to the documentation of this file.
00001 // This is core/vnl/vnl_random.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 //:
00006 //  \file
00007 
00008 #include "vnl_random.h"
00009 #include <vcl_ctime.h>
00010 #include <vcl_cmath.h>
00011 #include <vcl_cassert.h>
00012 
00013 unsigned long vnl_random::linear_congruential_lrand32()
00014 {
00015   return linear_congruential_previous = (linear_congruential_previous*linear_congruential_multiplier + 1)&0xffffffff;
00016 }
00017 
00018 //: Construct with seed
00019 vnl_random::vnl_random(unsigned long seed)
00020   : linear_congruential_previous(seed), mz_array_position(0UL), mz_borrow(0), mz_previous_normal_flag(0)
00021 {reseed(seed);}
00022 
00023 //: Construct with seed
00024 vnl_random::vnl_random(unsigned long seed[vnl_random_array_size])
00025   : mz_array_position(0UL), mz_borrow(0), mz_previous_normal_flag(0)
00026 {reseed(seed);}
00027 
00028 vnl_random::vnl_random(const vnl_random& r)
00029   : linear_congruential_previous(r.linear_congruential_previous)
00030   , mz_array_position(r.mz_array_position)
00031   , mz_borrow(r.mz_borrow)
00032   , mz_previous_normal_flag(r.mz_previous_normal_flag)
00033 {
00034   for (unsigned int i=0;i<vnl_random_array_size;++i)
00035   {
00036     mz_seed_array[i] = r.mz_seed_array[i];
00037     mz_array[i] = r.mz_array[i];
00038   }
00039 }
00040 
00041 vnl_random& vnl_random::operator=(const vnl_random& r)
00042 {
00043   linear_congruential_previous=r.linear_congruential_previous;
00044   mz_array_position=r.mz_array_position;
00045   mz_borrow=r.mz_borrow;
00046   mz_previous_normal_flag=r.mz_previous_normal_flag;
00047   for (unsigned int i=0;i<vnl_random_array_size;++i)
00048   {
00049     mz_seed_array[i] = r.mz_seed_array[i];
00050     mz_array[i] = r.mz_array[i];
00051   }
00052   return *this;
00053 }
00054 
00055 vnl_random::vnl_random() : mz_array_position(0UL), mz_borrow(0), mz_previous_normal_flag(0)
00056 {
00057   reseed();
00058 }
00059 
00060 vnl_random::~vnl_random()
00061 {
00062   for (unsigned int i=0;i<vnl_random_array_size;++i)
00063   {
00064     mz_seed_array[i] = 0;
00065     mz_array[i] = 0;
00066   }
00067 }
00068 
00069 void vnl_random::reseed()
00070 {
00071   reseed((unsigned long)vcl_time(NULL));
00072 }
00073 
00074 void vnl_random::reseed(unsigned long seed)
00075 {
00076   mz_array_position = 0UL;
00077   mz_borrow = 0;
00078 
00079   linear_congruential_previous = seed;
00080   // Use the lc generator to fill the array
00081   for (unsigned int i=0;i<vnl_random_array_size;++i)
00082   {
00083     mz_seed_array[i] = linear_congruential_lrand32();
00084     mz_array[i] = mz_seed_array[i];
00085   }
00086 
00087   // Warm up with 1000 randoms
00088   for (int j=0;j<1000;j++) lrand32();
00089 }
00090 
00091 void vnl_random::reseed(unsigned long seed[vnl_random_array_size])
00092 {
00093   mz_array_position = 0UL;
00094   mz_borrow = 0L;
00095 
00096   for (unsigned int i=0;i<vnl_random_array_size;++i)
00097   {
00098     mz_array[i] = seed[i];
00099     mz_seed_array[i] = seed[i];
00100   }
00101 }
00102 
00103 void vnl_random::restart()
00104 {
00105   mz_array_position = 0UL;
00106 
00107   for (unsigned int i=0;i<vnl_random_array_size;++i)
00108   {
00109     mz_array[i] = mz_seed_array[i];
00110   }
00111 }
00112 
00113 double vnl_random::normal()
00114 {
00115   if (mz_previous_normal_flag)
00116   {
00117     mz_previous_normal_flag = 0;
00118     return mz_previous_normal;
00119   }
00120   else
00121   {
00122     double x,y,r2;
00123     do
00124     {
00125       x = drand32(-1.0,1.0);
00126       y = drand32(-1.0,1.0);
00127       r2 = x*x+y*y;
00128     }
00129     while (r2 >=1.0 || r2 == 0.0);
00130     double fac = vcl_sqrt(-2.0*vcl_log(r2)/r2);
00131     mz_previous_normal = x*fac;
00132     mz_previous_normal_flag = 1;
00133     return y*fac;
00134   }
00135 }
00136 
00137 
00138 //: Random value from a unit normal distribution about zero
00139 // Uses a drand64() as its underlying generator.
00140 // Because the function uses a probability transform, the randomness (and
00141 // quantisation) is non-linearly dependent on the value. The further the sample
00142 // is from zero, the lower the number of bits on which it is random.
00143 double vnl_random::normal64()
00144 {
00145   if (mz_previous_normal_flag)
00146   {
00147     mz_previous_normal_flag = 0;
00148     return mz_previous_normal;
00149   }
00150   else
00151   {
00152     double x,y,r2;
00153     do
00154     {
00155       x = drand64(-1.0,1.0);
00156       y = drand64(-1.0,1.0);
00157       r2 = x*x+y*y;
00158     }
00159     while (r2 >=1.0 || r2 == 0.0);
00160     double fac = vcl_sqrt(-2.0*vcl_log(r2)/r2);
00161     mz_previous_normal = x*fac;
00162     mz_previous_normal_flag = 1;
00163     return y*fac;
00164   }
00165 }
00166 
00167 unsigned long vnl_random::lrand32()
00168 {
00169   unsigned long p1 = mz_array[(vnl_random_array_size + mz_array_position - mz_previous1)%vnl_random_array_size];
00170   unsigned long p2 = (p1 - mz_array[mz_array_position] - mz_borrow)&0xffffffff;
00171   if (p2 < p1) mz_borrow = 0;
00172   if (p2 > p1) mz_borrow = 1;
00173   mz_array[mz_array_position] = p2;
00174   mz_array_position = (mz_array_position+1)%vnl_random_array_size;
00175   return p2;
00176 }
00177 
00178 int vnl_random::lrand32(int lower, int upper)
00179 {
00180   assert(lower <= upper);
00181 
00182   // Note: we have to reject some numbers otherwise we get a very slight bias
00183   // towards the lower part of the range lower - upper. See below
00184 
00185   unsigned long range = upper-lower+1;
00186   unsigned long denom = 0xffffffff/range;
00187   unsigned long ran;
00188   while ((ran=lrand32()) >= denom*range) ;
00189   return lower + int(ran/denom);
00190 }
00191 
00192 
00193 int vnl_random::lrand32(int lower, int upper, int &count)
00194 {
00195   assert(lower <= upper);
00196 
00197   // Note: we have to reject some numbers otherwise we get a very slight bias
00198   // towards the lower part of the range lower - upper. Hence this is a "count"
00199   // version of the above function that returns the number of lrand32()
00200   // calls made.
00201 
00202   unsigned long range = upper-lower+1;
00203   unsigned long denom = 0xffffffff/range;
00204   unsigned long ran;
00205   count = 1;
00206   while ((ran=lrand32())>=denom*range) ++count;
00207   return lower + int(ran/denom);
00208 }
00209 
00210 double vnl_random::drand32(double lower, double upper)
00211 {
00212   assert(lower <= upper);
00213   return  (double(lrand32())/0xffffffff)*(upper-lower) + lower;
00214 }
00215 
00216 double vnl_random::drand64(double lower, double upper)
00217 {
00218   assert(lower <= upper);
00219   return  (double(lrand32())/0xffffffff + double(lrand32())/(double(0xffffffff)*double(0xffffffff)))*(upper-lower) + lower;
00220 }