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