2013-10-07 77 views
0

我正在嘗試編寫一個函數,該函數使用默認的RandomNumberGenerator實現在指定範圍內生成Int32值。將隨機字節轉換爲指定範圍內的整數

void GenerateRandom (int [] data, int minInclusive, int maxExclusive) 
{ 
    int size = 0; 
    int length = 0; 
    byte [] bytes = null; 

    size = (int) Math.Ceiling(Math.Log(Math.Abs(maxExclusive - minInclusive), 2)); 
    length = data.Length * size; 
    var bytes = new byte [length]; 

    using (RandomNumberGenerator generator = RandomNumberGenerator.Create()) 
    { 
     generator.GetBytes(bytes); 
    } 

    // How to effectively convert this `byte []` to an `int []` within the specified range? 
} 

的一種嘗試是產生長度(data.Length * ((int) Math.Ceiling(Math.Log(Math.Abs(maxExclusive - minInclusive), 2))))的隨機字節數組和字節的每x個結合到一個int。不管指定的範圍如何,這種方法當然有一個巨大的偏向於較大值的缺點,因爲多個最重要的字節幾乎不可能是零。

任何輸入,將不勝感激。雖然我在這裏使用.NET,但平臺/語言並不重要。尋找一個概念提示。

請注意,我已經熟悉.NET中的Random類,但我只想知道如何在使用RandomNumberGenerator的同時手動執行此操作。

+0

@MthetheWWatson:它是位於'System.Security.Cryptography'命名空間的抽象類。除非你想嘗試一下,否則你可以忽略這個問題。 –

+0

對不起,我發現剛剛發佈。 –

回答

1
unsafe static int[] GenerateRandom(int length, int minInclusive, int maxExclusive) 
{ 
    var bytes = new byte[length * 4]; 
    var ints = new int[length]; 

    var ratio = uint.MaxValue/(double)(maxExclusive - minInclusive); 

    using (RandomNumberGenerator generator = RandomNumberGenerator.Create()) 
    { 
     generator.GetBytes(bytes); 
     fixed(byte* b = bytes) 
     { 
      uint* i = (uint*)b; 
      for(int j = 0; j < length; j++, i++) 
      { 
       ints[j] = minInclusive + (int)(*i/ratio); 
      } 
     } 
    } 

    return ints; 
} 

我碰到一個小測試:

var ints = GenerateRandom(1000000, 0, 300); 

var groups = ints.GroupBy(x => x).Select(g => new { value = g.Key, count = g.Count() }); 
var hist = Enumerable.Range(0, 300).Join(groups, x => x, g => g.value, (x, g) => new { value = x, count = g.count }).ToList(); 

var max = hist.OrderByDescending(x => x.value).First(); 
var min = hist.First(); 

而且效果十分隨機所有數字0300之間,min.count = 3301max.count = 3358