c # modo più veloce per caso indice in un array
-
18-09-2019 - |
Domanda
Ho una matrice di valori doppi "vals", devo casualmente indice in questa matrice e ottenere un valore. GenRandomNumber () restituisce un numero compreso tra 0 e 1, ma mai 0 o 1. Sto usando Convert.ToInt32 per ottenere praticamente tutto a sinistra della mia decimale, ma ci deve essere un modo più efficiente di fare questo?
Ecco il mio codice:
public double GetRandomVal()
{
int z = Convert.ToInt32(GenRandomNumber() * (vals.Length));
return vals[z];
}
Grazie
Aggiorna
Grazie a tutti coloro che hanno risposto, ma sono costretto a utilizzare un Mersenne Twister implementazione numero casuale in dotazione, che ha il metodo rand.NextDouble ()
Aggiorna 2
Pensando a questo ancora, tutto che debba fare è gen un numero casuale tra 0 e Array.length-1 e quindi utilizzare tale indice casualmente nella matrice . lunghezza vals è 2 ^ 20 = 1048576 generando così un int casuale è sufficiente. Ho notato la mia Mersenne Twister ha un metodo:
public int Next(int maxValue)
Se io lo chiamo come vals [rand.Next (vals.length-1)] che dovrebbe farlo bene? Ho anche vedere il Mersenne Twister ha un costruttore:
public MersenneTwister(int[] init)
Non sono sicuro che questo è per, posso usare questo per precompilare i numeri casuali accettabili per il quale ho fornire una serie di 0 a vals.length?
FYI vals è un doppio array di lunghezza 1048576 partizionamento della curva di distribuzione normale. Sto usando questo meccanismo fondamentalmente per creare i numeri normalmente distribuite il più velocemente possibile, il Monte Carlo di simulazione utilizza miliardi di numeri casuali normalmente distribuite ogni giorno in modo ogni piccolo aiuto.
Soluzione
Provare a utilizzare un numero intero casuale invece:
Random random = new Random();
int randomNumber = random.Next(0, vals.Length);
return vals[randomNumber];
Altri suggerimenti
return vals[rng.Next(vals.Length)];
Dove RNG è
Random rng = new Random();
I pensi di avere la più semplice applicazione più diretta già individuato.
Ma se siete alla ricerca di miglioramento delle prestazioni nel vostro algoritmo di indicizzazione a caso, si può essere in grado di solo ' crepa ' IEEE 754 codificato doppio nel suo esponente e frazioni - e utilizzare la frazione modulo della dimensione dell'array come indice casuale.
Questa tecnica non è probabile che sia crittograficamente sicuro - quindi se questo è una considerazione -. Non farlo
Inoltre, questo approccio non rendere il codice più evidente - vorrei bastone con l'implementazione originale a meno massimizzare le prestazioni è la considerazione. Per inciso, la parte più lenta di questa elaborazione è più probabile che la generazione Mersenne Twister di numeri casuali.
Ecco il codice:
[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];
}
Hai pensato di usare la classe Random .NET?
Random.Next (Int32) , che restituisce un valore inferiore di ingresso e> = zero. Passare il tuo lunghezza della matrice come ingresso, e hai un indice valido casuale.
Come altre persone hanno già notato, System.Random ha un sovraccarico di Avanti che farà quello che stai chiedendo già.
Per quanto riguarda i suoi commenti su Convert.ToInt32
e un'alternativa più efficiente, si può lanciare direttamente un double
a un 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 non si è vincolo di utilizzare la funzione casuale, utilizzare la classe Random
.
public Double GetRandomValue(Double[] values)
{
return values[new Random().Next(values.Length)];
}
Altrimenti vorrei solo usare un cast perché dà il giusto comportamento -. Arrotondamento verso lo zero al posto del numero intero più vicino in quanto Convert.ToInt32()
fa
public Double GetRandomValue(Double[] values)
{
return values[(Int32)(GetNextRandomNumber() * values.Length)];
}