繁体   English   中英

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

[英]c# Fastest way to randomly index into an array

我有一个双值“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的双重数组,用于划分正态分布曲线。 我基本上使用这种机制来尽可能快地创建正态分布的数字, monte carlo模拟每天使用数十亿个正态分布的随机数,所以每一点都有帮助。

请尝试使用随机整数:

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

rng是哪里

Random rng = new Random();

我认为你已经确定了最简单,最直接的实现。

但是,如果您正在寻找随机索引算法中的性能提升,您可以将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];
}
private static readonly Random _random = new Random();

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

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

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

正如其他人已经注意到的那样,System.Random有一个Next重载,可以完成你已经提出的问题。

至于你对Convert.ToInt32的评论和更有效的替代方案,你可以直接将一个double转换为int

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

如果您不限制使用随机函数,请使用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)];
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM