c # maneira mais rápida para aleatoriamente índice em uma matriz
-
18-09-2019 - |
Pergunta
Eu tenho uma matriz de valores duplas "Vals", eu preciso índice aleatoriamente em essa matriz e obter um valor. GenRandomNumber () retorna um número entre 0 e 1, mas nunca 0 ou 1. Eu estou usando Convert.ToInt32 para obter basicamente tudo para a esquerda da minha casa decimal, mas deve haver uma maneira mais eficiente de fazer isso?
Aqui está o meu código:
public double GetRandomVal()
{
int z = Convert.ToInt32(GenRandomNumber() * (vals.Length));
return vals[z];
}
Graças
Atualização
Obrigado a todos aqueles que respondeu, mas sou obrigado a usar um MersenneTwister implementação de números aleatórios fornecido que tem método rand.NextDouble ()
Update 2
pensamento sobre esta um pouco mais, todos precisam I a fazer é
public int Next(int maxValue)
Se eu chamá-lo como vals [rand.Next (vals.length-1)] que deve fazê-lo direito? Vejo também o MersenneTwister tem um construtor:
public MersenneTwister(int[] init)
Não sei o que isso é para, posso usar isso para preencher previamente os números aleatórios aceitáveis ??para o qual eu proporcionar um leque de 0 a vals.length?
FYI valos é um duplo conjunto de comprimento 1048576 particionamento da curva de distribuição normal. Estou basicamente utilizando este mecanismo para criar números distribuídos normalmente o mais rápido possível, o Monte Carlo utiliza a simulação de milhares de milhões de Normalmente distribuído números aleatórios cada dia para cada pouco ajuda.
Solução
Tente usar um inteiro aleatório em vez disso:
Random random = new Random();
int randomNumber = random.Next(0, vals.Length);
return vals[randomNumber];
Outras dicas
return vals[rng.Next(vals.Length)];
Onde RNG é
Random rng = new Random();
Eu acho que você tem a mais simples aplicação mais direta já identificados.
Mas se você está procurando ganhos de desempenho em seu algoritmo de indexação aleatório, você pode ser capaz de apenas ' rachadura ' o IEEE 754 codificado duplo em seu expoente e fração - e usar a fração módulo do o tamanho da matriz como um índice aleatório.
Esta técnica não é susceptível de ser criptograficamente segura - por isso, se que é uma consideração -. Não fazê-lo
Além disso, esta abordagem não tornar o código mais óbvio - eu iria ficar com a sua aplicação original, a menos maximizando o desempenho é a consideração. Como um aparte, a parte mais lenta desse processamento é mais provável a geração Mersenne Twister de números aleatórios.
Aqui está o código:
[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];
}
Você já pensou em usar a classe .NET aleatória?
Gostaria de usar Random.Next (Int32) , que retorna um valor menor do que o de entrada e> = zero. Passar o seu comprimento de matriz como entrada, e você tem um índice válido aleatório.
Como outras pessoas já observamos, System.Random tem um Next sobrecarga que vai fazer o que você já está pedindo.
Quanto ao seu comentário sobre Convert.ToInt32
e uma alternativa mais eficiente, você pode diretamente lançar um double
a um int
:
double d = 1.5;
int i = (int)d;
private static readonly Random _random = new Random();
public double GetRandomVal()
{
int z = _random.Next(vals.Length);
return vals[z];
}
Se você não tem restrição de usar a função aleatório, use a classe Random
.
public Double GetRandomValue(Double[] values)
{
return values[new Random().Next(values.Length)];
}
Else gostaria apenas de usar um elenco porque dá o comportamento correto -. Arredondamento para zero, em vez do número inteiro mais próximo como Convert.ToInt32()
faz
public Double GetRandomValue(Double[] values)
{
return values[(Int32)(GetNextRandomNumber() * values.Length)];
}