The Labs \ Source Viewer \ SSCLI \ System \ Random

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. /*============================================================
  16. **
  17. ** Class:  Random
  18. **
  19. **
  20. ** Purpose: A random number generator.
  21. **
  22. **
  23. ===========================================================*/
  24. namespace System
  25. {
  26.    
  27.     using System;
  28.     using System.Runtime.CompilerServices;
  29.     using System.Globalization;
  30.     [System.Runtime.InteropServices.ComVisible(true)]
  31.     [Serializable()]
  32.     public class Random
  33.     {
  34.         //
  35.         // Private Constants
  36.         //
  37.         private const int MBIG = Int32.MaxValue;
  38.         private const int MSEED = 161803398;
  39.         private const int MZ = 0;
  40.        
  41.        
  42.         //
  43.         // Member Variables
  44.         //
  45.         private int inext, inextp;
  46.         private int[] SeedArray = new int[56];
  47.        
  48.         //
  49.         // Public Constants
  50.         //
  51.        
  52.         //
  53.         // Native Declarations
  54.         //
  55.        
  56.         //
  57.         // Constructors
  58.         //
  59.        
  60.         public Random() : this(Environment.TickCount)
  61.         {
  62.         }
  63.        
  64.         public Random(int Seed)
  65.         {
  66.             int ii;
  67.             int mj;
  68.             int mk;
  69.            
  70.             //Initialize our Seed array.
  71.             //This algorithm comes from Numerical Recipes in C (2nd Ed.)
  72.             mj = MSEED - Math.Abs(Seed);
  73.             SeedArray[55] = mj;
  74.             mk = 1;
  75.             for (int i = 1; i < 55; i++) {
  76.                 //Apparently the range [1..55] is special (Knuth) and so we're wasting the 0'th position.
  77.                 ii = (21 * i) % 55;
  78.                 SeedArray[ii] = mk;
  79.                 mk = mj - mk;
  80.                 if (mk < 0)
  81.                     mk += MBIG;
  82.                 mj = SeedArray[ii];
  83.             }
  84.             for (int k = 1; k < 5; k++) {
  85.                 for (int i = 1; i < 56; i++) {
  86.                     SeedArray[i] -= SeedArray[1 + (i + 30) % 55];
  87.                     if (SeedArray[i] < 0)
  88.                         SeedArray[i] += MBIG;
  89.                 }
  90.             }
  91.             inext = 0;
  92.             inextp = 21;
  93.             Seed = 1;
  94.         }
  95.        
  96.         //
  97.         // Package Private Methods
  98.         //
  99.        
  100. /*====================================Sample====================================
  101.       **Action: Return a new random number [0..1) and reSeed the Seed array.
  102.       **Returns: A double [0..1)
  103.       **Arguments: None
  104.       **Exceptions: None
  105.       ==============================================================================*/       
  106.         protected virtual double Sample()
  107.         {
  108.             //Including this division at the end gives us significantly improved
  109.             //random number distribution.
  110.             return (InternalSample() * (1.0 / MBIG));
  111.         }
  112.        
  113.         private int InternalSample()
  114.         {
  115.             int retVal;
  116.             int locINext = inext;
  117.             int locINextp = inextp;
  118.            
  119.             if (++locINext >= 56)
  120.                 locINext = 1;
  121.             if (++locINextp >= 56)
  122.                 locINextp = 1;
  123.            
  124.             retVal = SeedArray[locINext] - SeedArray[locINextp];
  125.            
  126.             if (retVal < 0)
  127.                 retVal += MBIG;
  128.            
  129.             SeedArray[locINext] = retVal;
  130.            
  131.             inext = locINext;
  132.             inextp = locINextp;
  133.            
  134.             return retVal;
  135.         }
  136.        
  137.         //
  138.         // Public Instance Methods
  139.         //
  140.        
  141.        
  142. /*=====================================Next=====================================
  143.       **Returns: An int [0..Int32.MaxValue)
  144.       **Arguments: None
  145.       **Exceptions: None.
  146.       ==============================================================================*/       
  147.         public virtual int Next()
  148.         {
  149.             return InternalSample();
  150.         }
  151.        
  152.         private double GetSampleForLargeRange()
  153.         {
  154.             // The distribution of double value returned by Sample
  155.             // is not distributed well enough for a large range.
  156.             // If we use Sample for a range [Int32.MinValue..Int32.MaxValue)
  157.             // We will end up getting even numbers only.
  158.            
  159.             int result = InternalSample();
  160.             // Note we can't use addition here. The distribution will be bad if we do that.
  161.             bool negative = (InternalSample() % 2 == 0) ? true : false;
  162.             // decide the sign based on second sample
  163.             if (negative) {
  164.                 result = -result;
  165.             }
  166.             double d = result;
  167.             d += (Int32.MaxValue - 1);
  168.             // get a number in range [0 .. 2 * Int32MaxValue - 1)
  169.             d /= 2 * (uint)Int32.MaxValue - 1;
  170.             return d;
  171.         }
  172.        
  173.        
  174. /*=====================================Next=====================================
  175.       **Returns: An int [minvalue..maxvalue)
  176.       **Arguments: minValue -- the least legal value for the Random number.
  177.       **          maxValue -- One greater than the greatest legal return value.
  178.       **Exceptions: None.
  179.       ==============================================================================*/       
  180.         public virtual int Next(int minValue, int maxValue)
  181.         {
  182.             if (minValue > maxValue) {
  183.                 throw new ArgumentOutOfRangeException("minValue", String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Argument_MinMaxValue"), "minValue", "maxValue"));
  184.             }
  185.            
  186.             long range = (long)maxValue - minValue;
  187.             if (range <= (long)Int32.MaxValue) {
  188.                 return ((int)(Sample() * range) + minValue);
  189.             }
  190.             else {
  191.                 return (int)((long)(GetSampleForLargeRange() * range) + minValue);
  192.             }
  193.         }
  194.        
  195.        
  196. /*=====================================Next=====================================
  197.       **Returns: An int [0..maxValue)
  198.       **Arguments: maxValue -- One more than the greatest legal return value.
  199.       **Exceptions: None.
  200.       ==============================================================================*/       
  201.         public virtual int Next(int maxValue)
  202.         {
  203.             if (maxValue < 0) {
  204.                 throw new ArgumentOutOfRangeException("maxValue", String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("ArgumentOutOfRange_MustBePositive"), "maxValue"));
  205.             }
  206.             return (int)(Sample() * maxValue);
  207.         }
  208.        
  209.        
  210. /*=====================================Next=====================================
  211.       **Returns: A double [0..1)
  212.       **Arguments: None
  213.       **Exceptions: None
  214.       ==============================================================================*/       
  215.         public virtual double NextDouble()
  216.         {
  217.             return Sample();
  218.         }
  219.        
  220.        
  221. /*==================================NextBytes===================================
  222.       **Action:  Fills the byte array with random bytes [0..0x7f].  The entire array is filled.
  223.       **Returns:Void
  224.       **Arugments:  buffer -- the array to be filled.
  225.       **Exceptions: None
  226.       ==============================================================================*/       
  227.         public virtual void NextBytes(byte[] buffer)
  228.         {
  229.             if (buffer == null)
  230.                 throw new ArgumentNullException("buffer");
  231.             for (int i = 0; i < buffer.Length; i++) {
  232.                 buffer[i] = (byte)(InternalSample() % (Byte.MaxValue + 1));
  233.             }
  234.         }
  235.     }
  236.    
  237.    
  238.    
  239. }

Developer Fusion