3

我有一个双值数组“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 之间的随机数,然后使用它随机索引到 array。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 的数组吗?

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

4

8 回答 8

12

尝试使用随机整数:

Random random = new Random();
int randomNumber = random.Next(0, vals.Length);
return vals[randomNumber];
于 2009-07-20T17:41:32.193 回答
3
返回 vals[rng.Next(vals.Length)];

rng 在哪里

随机 rng = new Random();

于 2009-07-20T17:42:05.560 回答
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];
}
于 2009-07-20T18:38:31.390 回答
0
private static readonly Random _random = new Random();

public double GetRandomVal()
{
    int z = _random.Next(vals.Length);
    return vals[z];
}
于 2009-07-20T17:42:34.280 回答
0

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

于 2009-07-20T17:42:46.357 回答
0

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

于 2009-07-20T17:43:21.487 回答
0

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

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

double d = 1.5;
int i = (int)d;
于 2009-07-20T17:44:23.933 回答
-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)];
}
于 2009-07-20T17:43:51.703 回答