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.

È stato utile?

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)];
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top