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?
}

1 つの試みは、長さのランダムなバイト配列を生成し、(data.Length * ((int) Math.Ceiling(Math.Log(Math.Abs(maxExclusive - minInclusive), 2))))各 x 個のバイトを int に結合することでした。指定された範囲に関係なく、このアプローチにはもちろん、複数の最上位バイトがゼロになる可能性がほとんどないため、より大きな値に大きく偏るという欠点があります。

任意の入力をいただければ幸いです。ここでは .NET を使用していますが、プラットフォームや言語は問いません。概念的なヒントを探しています。

私は既に .NET の Random クラスに精通していますが、RandomNumberGenerator を使用できる一方で、これを手動で行う方法を理解することにのみ関心があることに注意してください。

4

1 に答える 1

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();

そして、結果はととの間のすべての数値で非常にランダムです。0300min.count = 3301max.count = 3358

于 2013-12-08T05:50:02.707 に答える