c#随机索引到数组的最快方法

时间:2009-07-20 17:39:59

标签: c# arrays random random-access

我有一个双值“vals”数组,我需要随机索引到这个数组并得到一个值。 GenRandomNumber()返回一个介于0和1之间但从不为0或1的数字。我使用Convert.ToInt32基本上得到了小数点左边的所有内容,但必须有更有效的方法吗?

这是我的代码:

public double GetRandomVal()
{
   int z = Convert.ToInt32(GenRandomNumber() * (vals.Length));
   return vals[z];
}

由于

更新

感谢所有回复的人,但我不得不使用提供方法rand.NextDouble()的提供的MersenneTwister随机数实现

更新2

再考虑一下,我需要做的就是生成0和array.length-1之间的随机数,然后使用它随机索引到数组。 vals长度为2 ^ 20 = 1048576,因此生成随机int就足够了。我注意到我的MersenneTwister有一个方法:

public int Next(int maxValue)

如果我把它称为 vals [rand.Next(vals.length-1)] 那应该做对吗?我也看到MersenneTwister有一个构造函数:

public MersenneTwister(int[] init)

不确定这是为了什么,我可以用它来预先填充我提供0到vals.length的数组的可接受的随机数吗?

FYI vals是一个长度为1048576的双重数组,用于划分正态分布曲线。我基本上使用这种机制来尽可能快地创建正态分布的数字,蒙特卡罗模拟每天使用数十亿个正态分布的随机数,所以每一点都有帮助。

8 个答案:

答案 0 :(得分:9)

尝试使用随机整数:

Random random = new Random();
int randomNumber = random.Next(0, vals.Length);
return vals[randomNumber];

答案 1 :(得分:3)

return vals[rng.Next(vals.Length)];

其中rng是

Random rng = new Random();

答案 2 :(得分:2)

我认为您已经确定了最简单,最直接的实施方案。

但是,如果您正在寻找随机索引算法中的性能提升,您可能只需将<破解'IEEE 754编码的双精度转换为其指数和分数 - 并使用模数的分数数组大小为随机索引。

这种技术不太可能是加密安全的 - 所以如果这是一个考虑因素 - 不要这样做。

此外,这种方法不会使代码更加明显 - 我会坚持原始的实现,除非考虑最大化性能。顺便说一句,这个处理过程中最慢的部分很可能就是Mersenne Twister随机数的产生。

以下是代码:

[StructLayout(LayoutKind.Explicit)] // used create a union of Long and Double
public struct IEEE754
{
    private const ulong SIGN_BITS     = 0x8000000000000000;
    private const ulong EXPONENT_BITS = 0x7FF0000000000000;
    private const ulong FRACTION_BITS = 0x000FFFFFFFFFFFFF;

    private const int SIGN_OFFSET     = 63;
    private const int EXPONENT_OFFSET = 52;

    // [FieldOffset] attribute is .NET's way of defining how to explicitly
    // layout the fields of a structure - we're using it to overlay the
    // double and long into a single bit-space ... effectively a C# 'union'
    [FieldOffset( 0 )] private double DoubleValue;
    [FieldOffset( 0 )] private ulong LongValue;

    public IEEE754(double val)
    {
        DoubleValue = val;
    }
    // properties that retrieve the various pieces of an IEEE754 double
    public long Fraction { get { return (long)(LongValue & FRACTION_BITS); } }
    public long Exponent { get { return (long)((LongValue & EXPONENT_BITS) >> EXPONENT_OFFSET); } }
    public long Sign     { get { return (long)((LongValue & SIGN_BITS) >> SIGN_OFFSET); } }

    public void Set( double val ) { DoubleValue = val; }
}

public static void TestFunction()
{
    var array = Enumerable.Range( 1, 10000 ).ToArray();   // test array...

    // however you access your random generator would go here...
    var rand = new YourRandomNumberGenerator();

    // crack the double using the special union structure we created...
    var dul = new IEEE754( rand.GenRandomNumber() );

    // use the factional value modulo the array length as a random index...
    var randomValue = array[dul.Fraction % array.Length];
}

答案 3 :(得分:0)

private static readonly Random _random = new Random();

public double GetRandomVal()
{
    int z = _random.Next(vals.Length);
    return vals[z];
}

答案 4 :(得分:0)

您是否考虑过使用.NET Random类?

答案 5 :(得分:0)

我会使用Random.Next(Int32),它会返回一个小于输入值且&gt; = 0的值。将您的数组长度作为输入传递,并且您有一个随机有效索引。

答案 6 :(得分:0)

正如其他人已经注意到的那样,System.Random有一个Next重载,可以满足您的要求。

关于您对Convert.ToInt32的评论以及更有效的替代方案,您可以直接将double投放到int

double d = 1.5;
int i = (int)d;

答案 7 :(得分:-1)

如果您不限制使用随机函数,请使用Random类。

public Double GetRandomValue(Double[] values)
{
    return values[new Random().Next(values.Length)];
}

否则我只会使用强制转换,因为它给出了正确的行为 - 向零舍入而不是Convert.ToInt32()的最接近的整数。

public Double GetRandomValue(Double[] values)
{
    return values[(Int32)(GetNextRandomNumber() * values.Length)];
}