Advertisement
Hadlock

random number generator c#

May 25th, 2015
422
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 8.41 KB | None | 0 0
  1. using System;
  2.  
  3. namespace TestSimpleRNG
  4. {
  5.     /// <summary>
  6.     /// SimpleRNG is a simple random number generator based on
  7.     /// George Marsaglia's MWC (multiply with carry) generator.
  8.     /// Although it is very simple, it passes Marsaglia's DIEHARD
  9.     /// series of random number generator tests.
  10.     ///
  11.     /// Written by John D. Cook
  12.     /// http://www.johndcook.com
  13.     /// </summary>
  14.     public class SimpleRNG
  15.     {
  16.         private static uint m_w;
  17.         private static uint m_z;
  18.  
  19.         static SimpleRNG()
  20.         {
  21.             // These values are not magical, just the default values Marsaglia used.
  22.             // Any pair of unsigned integers should be fine.
  23.             m_w = 521288629;
  24.             m_z = 362436069;
  25.         }
  26.  
  27.         // The random generator seed can be set three ways:
  28.         // 1) specifying two non-zero unsigned integers
  29.         // 2) specifying one non-zero unsigned integer and taking a default value for the second
  30.         // 3) setting the seed from the system time
  31.  
  32.         public static void SetSeed(uint u, uint v)
  33.         {
  34.             if (u != 0) m_w = u;
  35.             if (v != 0) m_z = v;
  36.         }
  37.  
  38.         public static void SetSeed(uint u)
  39.         {
  40.             m_w = u;
  41.         }
  42.  
  43.         public static void SetSeedFromSystemTime()
  44.         {
  45.             System.DateTime dt = System.DateTime.Now;
  46.             long x = dt.ToFileTime();
  47.             SetSeed((uint)(x >> 16), (uint)(x % 4294967296));
  48.         }
  49.  
  50.         // Produce a uniform random sample from the open interval (0, 1).
  51.         // The method will not return either end point.
  52.         public static double GetUniform()
  53.         {
  54.             // 0 <= u < 2^32
  55.             uint u = GetUint();
  56.             // The magic number below is 1/(2^32 + 2).
  57.             // The result is strictly between 0 and 1.
  58.             return (u + 1.0) * 2.328306435454494e-10;
  59.         }
  60.  
  61.         // This is the heart of the generator.
  62.         // It uses George Marsaglia's MWC algorithm to produce an unsigned integer.
  63.         // See http://www.bobwheeler.com/statistics/Password/MarsagliaPost.txt
  64.         private static uint GetUint()
  65.         {
  66.             m_z = 36969 * (m_z & 65535) + (m_z >> 16);
  67.             m_w = 18000 * (m_w & 65535) + (m_w >> 16);
  68.             return (m_z << 16) + m_w;
  69.         }
  70.        
  71.         // Get normal (Gaussian) random sample with mean 0 and standard deviation 1
  72.         public static double GetNormal()
  73.         {
  74.             // Use Box-Muller algorithm
  75.             double u1 = GetUniform();
  76.             double u2 = GetUniform();
  77.             double r = Math.Sqrt( -2.0*Math.Log(u1) );
  78.             double theta = 2.0*Math.PI*u2;
  79.             return r*Math.Sin(theta);
  80.         }
  81.        
  82.         // Get normal (Gaussian) random sample with specified mean and standard deviation
  83.         public static double GetNormal(double mean, double standardDeviation)
  84.         {
  85.             if (standardDeviation <= 0.0)
  86.             {
  87.                 string msg = string.Format("Shape must be positive. Received {0}.", standardDeviation);
  88.                 throw new ArgumentOutOfRangeException(msg);
  89.             }
  90.             return mean + standardDeviation*GetNormal();
  91.         }
  92.        
  93.         // Get exponential random sample with mean 1
  94.         public static double GetExponential()
  95.         {
  96.             return -Math.Log( GetUniform() );
  97.         }
  98.  
  99.         // Get exponential random sample with specified mean
  100.         public static double GetExponential(double mean)
  101.         {
  102.             if (mean <= 0.0)
  103.             {
  104.                 string msg = string.Format("Mean must be positive. Received {0}.", mean);
  105.                 throw new ArgumentOutOfRangeException(msg);
  106.             }
  107.             return mean*GetExponential();
  108.         }
  109.  
  110.         public static double GetGamma(double shape, double scale)
  111.         {
  112.             // Implementation based on "A Simple Method for Generating Gamma Variables"
  113.             // by George Marsaglia and Wai Wan Tsang.  ACM Transactions on Mathematical Software
  114.             // Vol 26, No 3, September 2000, pages 363-372.
  115.  
  116.             double d, c, x, xsquared, v, u;
  117.  
  118.             if (shape >= 1.0)
  119.             {
  120.                 d = shape - 1.0/3.0;
  121.                 c = 1.0/Math.Sqrt(9.0*d);
  122.                 for (;;)
  123.                 {
  124.                     do
  125.                     {
  126.                         x = GetNormal();
  127.                         v = 1.0 + c*x;
  128.                     }
  129.                     while (v <= 0.0);
  130.                     v = v*v*v;
  131.                     u = GetUniform();
  132.                     xsquared = x*x;
  133.                     if (u < 1.0 -.0331*xsquared*xsquared || Math.Log(u) < 0.5*xsquared + d*(1.0 - v + Math.Log(v)))
  134.                         return scale*d*v;
  135.                 }
  136.             }
  137.             else if (shape <= 0.0)
  138.             {
  139.                 string msg = string.Format("Shape must be positive. Received {0}.", shape);
  140.                 throw new ArgumentOutOfRangeException(msg);
  141.             }
  142.             else
  143.             {
  144.                 double g = GetGamma(shape+1.0, 1.0);
  145.                 double w = GetUniform();
  146.                 return scale*g*Math.Pow(w, 1.0/shape);
  147.             }
  148.         }
  149.  
  150.         public static double GetChiSquare(double degreesOfFreedom)
  151.         {
  152.             // A chi squared distribution with n degrees of freedom
  153.             // is a gamma distribution with shape n/2 and scale 2.
  154.             return GetGamma(0.5 * degreesOfFreedom, 2.0);
  155.         }
  156.  
  157.         public static double GetInverseGamma(double shape, double scale)
  158.         {
  159.             // If X is gamma(shape, scale) then
  160.             // 1/Y is inverse gamma(shape, 1/scale)
  161.             return 1.0 / GetGamma(shape, 1.0 / scale);
  162.         }
  163.  
  164.         public static double GetWeibull(double shape, double scale)
  165.         {
  166.             if (shape <= 0.0 || scale <= 0.0)
  167.             {
  168.                 string msg = string.Format("Shape and scale parameters must be positive. Recieved shape {0} and scale{1}.", shape, scale);
  169.                 throw new ArgumentOutOfRangeException(msg);
  170.             }
  171.             return scale * Math.Pow(-Math.Log(GetUniform()), 1.0 / shape);
  172.         }
  173.  
  174.         public static double GetCauchy(double median, double scale)
  175.         {
  176.             if (scale <= 0)
  177.             {
  178.                 string msg = string.Format("Scale must be positive. Received {0}.", scale);
  179.                 throw new ArgumentException(msg);
  180.             }
  181.  
  182.             double p = GetUniform();
  183.  
  184.             // Apply inverse of the Cauchy distribution function to a uniform
  185.             return median + scale*Math.Tan(Math.PI*(p - 0.5));
  186.         }
  187.  
  188.         public static double GetStudentT(double degreesOfFreedom)
  189.         {
  190.             if (degreesOfFreedom <= 0)
  191.             {
  192.                 string msg = string.Format("Degrees of freedom must be positive. Received {0}.", degreesOfFreedom);
  193.                 throw new ArgumentException(msg);
  194.             }
  195.  
  196.             // See Seminumerical Algorithms by Knuth
  197.             double y1 = GetNormal();
  198.             double y2 = GetChiSquare(degreesOfFreedom);
  199.             return y1 / Math.Sqrt(y2 / degreesOfFreedom);
  200.         }
  201.  
  202.         // The Laplace distribution is also known as the double exponential distribution.
  203.         public static double GetLaplace(double mean, double scale)
  204.         {
  205.             double u = GetUniform();
  206.             return (u < 0.5) ?
  207.                 mean + scale*Math.Log(2.0*u) :
  208.                 mean - scale*Math.Log(2*(1-u));
  209.         }
  210.  
  211.         public static double GetLogNormal(double mu, double sigma)
  212.         {
  213.             return Math.Exp(GetNormal(mu, sigma));
  214.         }
  215.  
  216.         public static double GetBeta(double a, double b)
  217.         {
  218.             if (a <= 0.0 || b <= 0.0)
  219.             {
  220.                 string msg = string.Format("Beta parameters must be positive. Received {0} and {1}.", a, b);
  221.                 throw new ArgumentOutOfRangeException(msg);
  222.             }
  223.  
  224.             // There are more efficient methods for generating beta samples.
  225.             // However such methods are a little more efficient and much more complicated.
  226.             // For an explanation of why the following method works, see
  227.             // http://www.johndcook.com/distribution_chart.html#gamma_beta
  228.  
  229.             double u = GetGamma(a, 1.0);
  230.             double v = GetGamma(b, 1.0);
  231.             return u / (u + v);
  232.         }
  233.     }
  234. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement