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

发布于 2024-07-27 22:34:58 字数 1007 浏览 7 评论 0原文

我有一个双值“vals”数组,我需要随机索引到该数组并获取一个值。 GenRandomNumber() 返回 0 到 1 之间的数字,但绝不是 0 或 1。我使用 Convert.ToInt32 基本上将所有内容都放在小数点左侧,但必须有更有效的方法来执行此操作吗?

这是我的代码:

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

感谢

更新

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

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

I have an array of double values "vals", I need to randomly index into this array and get a value. GenRandomNumber() returns a number between 0 and 1 but never 0 or 1. I am using Convert.ToInt32 to basically get everything to the left of my decimal place, but there must be a more efficient way of doing this?

Here's my code:

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

Thanks

Update

Thanks to all those who have replied, but I am constrained to use a supplied MersenneTwister random number implementation that has method rand.NextDouble()

Update 2

Thinking about this some more, all I need to do is gen a random number between 0 and array.length-1 and then use that to randomly index into the array. vals length is 2^20 = 1048576 so generating a random int is sufficient. I notice my MersenneTwister has a method:

public int Next(int maxValue)

If I call it like vals[rand.Next(vals.length-1)] that should do it right? I also see the MersenneTwister has a constructor:

public MersenneTwister(int[] init)

Not sure what this is for, can I use this to prepopulate the acceptable random numbers for which I provide an array of 0 to vals.length?

FYI vals is a double array of length 1048576 partitioning the normal distribution curve. I am basically using this mechanism to create Normally distributed numbers as fast as possible, the monte carlo simulation uses billions of Normally distributed random numbers every day so every little bit helps.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

嘿看小鸭子会跑 2024-08-03 22:34:59

尝试使用随机整数代替:

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

Try using a random integer instead:

Random random = new Random();
int randomNumber = random.Next(0, vals.Length);
return vals[randomNumber];
蒲公英的约定 2024-08-03 22:34:59
return vals[rng.Next(vals.Length)];

其中 rng 是

Random rng = new Random();

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

Where rng is

Random rng = new Random();

一百个冬季 2024-08-03 22:34:59

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

但是,如果您正在寻求随机索引算法的性能提升,您也许可以将 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];
}

I think you have the simplest most direct implementation already identified.

But if you are looking for performance gains in your random indexing algorithm, you may be able to just 'crack' the IEEE 754 encoded double into its exponent and fraction - and use the fraction modulo the array size as a random index.

This technique IS NOT likely to be cryptographically secure - so if that is a consideration - don't do it.

Also, this approach DOES NOT make the code more obvious - I would stick with your original implementation unless maximizing performance is the consideration. As an aside, the slowest part of this processing is most likely the Mersenne Twister generation of random numbers.

Here's the code:

[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];
}
南汐寒笙箫 2024-08-03 22:34:59

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

Have you considered using the .NET Random class?

南城旧梦 2024-08-03 22:34:59

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

I would use Random.Next(Int32), which returns a value less than the input and >= zero. Pass your array length as the input, and you've got a random valid index.

相权↑美人 2024-08-03 22:34:59

正如其他人已经指出的那样,System.Random 有一个 Next 重载,它将执行您已经要求的操作。

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

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

As other people have already noted, System.Random has a Next overload that will do what you're asking already.

As to your comment about Convert.ToInt32 and a more efficient alternative, you can directly cast a double to an int:

double d = 1.5;
int i = (int)d;
樱花落人离去 2024-08-03 22:34:59
private static readonly Random _random = new Random();

public double GetRandomVal()
{
    int z = _random.Next(vals.Length);
    return vals[z];
}
private static readonly Random _random = new Random();

public double GetRandomVal()
{
    int z = _random.Next(vals.Length);
    return vals[z];
}
末蓝 2024-08-03 22:34:59

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

If you are not constraint to use your random function, use the Random class.

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

Else I would just use a cast because it gives the right behavior - rounding towards zero instead of the closest integer as Convert.ToInt32() does.

public Double GetRandomValue(Double[] values)
{
    return values[(Int32)(GetNextRandomNumber() * values.Length)];
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文