2009-07-22 12 views
7

Finora ho usato il C# Mersenne Twister trovato qui per generare numeri casuali:C# Mersenne Twister implementazione generatore numero intero casuale (SFMT) simulazione Monte Carlo

http://www.centerspace.net/resources.php

Ho appena scoperto SFMT che è dovrebbe essere due volte più veloce qui:

http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/

Qualcuno può indicarmi un'implementazione C# di SFMT?

I miei requisiti sono di generare un numero intero compreso tra (e compreso) 0 e 2^20 (1048576).

ho bisogno di fare questo bilioni di volte tutti i giorni per una simulazione in esecuzione su un orologio di 24 ore, quindi sono disposti a spendere giorni tweaking questo alla perfezione.

Attualmente ho modificato il Centro Spaziale Mersenne Twister con l'aggiunta di un nuovo metodo per soddisfare le mie esigenze:

public uint Next20() 
{    
    return (uint)(genrand_int32() >> 12); 
} 

Utilizzando il metodo genrand_int32() mi piacerebbe produrre la mia versione, genrand_int20(), che genera un intero tra (e compreso) 0 e 2^20 per salvare sulla trasmissione sopra e spostare ma non capisco la matematica. Esattamente come posso fare questo?

Inoltre si sta utilizzando un uint che sarà più veloce di quello o è solo una questione di numeri indirizzabili? Perché ho solo bisogno di un massimo di 1048576, mi interessa solo la velocità.

Anche questo sarà in esecuzione su un 2003 R2 SP2 scatola (32 bit) di Windows Server con .NET 2. Il processore è AMD Opteron 275 (4 core).

+0

Un numero a 20 bit rappresenterà la gamma 0-2^20-1 inclusiva, 2^20 richiede 21 bit per rappresentare (un 1 seguito da 20 zeri) –

+1

Nifle: Non confondere il * periodo * del generatore (che è la lunghezza della sequenza) con un * intervallo * in cui si desidera numeri casuali. – Joey

+0

@Patrick grazie sei corretto 2^20-1 è quello che mi serve, ho bisogno di indicizzare casualmente in una matrice di lunghezza 2^20. – m3ntat

risposta

5

Quello che puoi fare è scaricare il source from the link che hai scoperto su Code Project. Decomprimilo, carica la soluzione in Visual Studio e compila. Questo ti darà sorgente, una cll non gestita e un file .lib.

È possibile P/Richiamare le funzioni in questa DLL, (sono esportate solo 5 funzioni semplici, di cui sono necessarie solo due) oppure è possibile utilizzare questa dll, lib e il file di intestazione SFMT per creare un wrapper gestito dll puoi usare in C# senza P/Invoke. Ho appena provato questo metodo ed è stato molto semplice da fare. Non è stato coinvolto il marshalling esplicito.

Ecco come. Dopo aver scaricato e compilato la sorgente (sono necessari l'intestazione e il file lib creato in aggiunta alla DLL), creare un nuovo progetto Libreria di classi C++ CLR. Chiamalo WrapSFMT o qualcosa del genere. Vai alle proprietà del progetto. In Intestazioni precompilate in C++, passare a "Non utilizzare intestazioni precompilate". Sotto Linker/General/Additional Library Directories, immettere il percorso per SFMT.lib. Sotto linker/input/dipendenze aggiuntive, aggiungere SFMT.lib. Chiudi le pagine delle proprietà. Copia SFMT.h nella cartella del progetto e includilo nel progetto.

Modifica WrapSFMT.h per leggere come segue:

#pragma once 
#include "SFMT.H" 

using namespace System; 

namespace WrapSFMT { 

public ref class SRandom 
{ 
public:SRandom(UInt32); 
public:UInt32 Rand32(void); 
}; 
} 

Questi dichiarare i metodi che saranno nella tua classe. Ora modificare WrapSFMT.cpp a leggere:

#include "WrapSFMT.h" 

namespace WrapSFMT { 

SRandom::SRandom(UInt32 seed) 
{ 
    init_gen_rand(seed); 
} 

UInt32 SRandom::Rand32() 
{ 
    return gen_rand32(); 
} 
} 

Questi implementare i metodi dichiarati nel file di intestazione. Tutto quello che stai facendo è chiamare le funzioni da SFMT.dll e C++/CLI gestisce automaticamente la conversione da non gestita a gestita. Ora dovresti essere in grado di costruire WrapSFMT.dll e farne riferimento nel tuo progetto C#. Assicurati che SFMT.dll si trovi nel percorso e non dovresti avere problemi.

+0

Ho scaricato le sue DLL e ho provato ad aggiungerle come riferimento al mio progetto C#: --------------------------- Microsoft Visual Studio --------------------------- Non è stato possibile aggiungere un riferimento a "SFMTc.dll". Assicurati che il file sia accessibile e che sia un assembly valido o un componente COM. --------------------------- OK ------------------- -------- Qualche idea? su come utilizzare questo e chiamarlo nel modo più efficiente da Visual Studio – m3ntat

+0

Ok ho inserito la DLL nella mia cartella bin e ho il codice: [DllImport ("SFMTc.dll")] extern statico UInt32 gen_rand32(); Questa chiamata senza errori ma tutto ciò che ottengo è 0, mai nessun altro numero. – m3ntat

+0

Se si desidera utilizzare P/Invoke, è necessario richiamare due funzioni, init_gen_rand (UInt32), inizializzando il generatore con un seme, e quindi è possibile chiamare gen_rand32() quanto desiderato. (ma probabilmente non dovresti superare il periodo di Mersenne Twister) –

0

Non vedo davvero il tuo problema con la velocità qui. Sulla mia macchina (Core 2 Duo T7200 @ 2 GHz) la generazione di un numero intero casuale con MT19937 o MT19937-64 richiede circa 20 ns (in media, quando si disegnano numeri 50000). Quindi sarebbe circa 4,32 × 10 (quindi circa 4 trilioni di numeri) al giorno. E questo è per un nucleo. Con Java. Quindi penso che puoi aspettarti che le prestazioni siano più che adeguate alle tue esigenze.

Per rispondere effettivamente alla tua domanda: non conosco un'implementazione C# di SFMT, ma la conversione del codice C in C# dovrebbe essere abbastanza semplice. Tuttavia, non stai ottenendo molto, dato che SFMT è ottimizzato per SIMD e C# attualmente non supporta direttamente questo.

+0

Ho calcolato i requisiti del numero casuale giornaliero per questa simulazione per supportare l'azienda a 1,645,668,000,000. La simulazione fa molte altre cose, principalmente la moltiplicazione della matrice, quindi non posso dedicare tutto il tempo della CPU alla generazione di numeri casuali, ovviamente voglio minimizzare il maggior numero possibile di numeri casuali, da qui la Stackoverflow Question. – m3ntat

+1

Bene, hai ancora più core e le simulazioni Monte Carlo tendono ad essere abbastanza parallelizzabili.Direi che dovresti prima andare avanti e risolvere il tuo problema e rivisitare le singole parti della soluzione se dimostrano di essere un problema di prestazioni. – Joey

+0

Per SFMT non me ne sono reso conto, forse il mio approccio migliore è provare a compilare la versione c qui: http://www.math.sci.hiroshima-u.ac.jp/~m-mat/bin/dl/ dl.cgi? SFMT: SFMT-src-1.3.3.zip e quindi utilizzarlo in qualche modo dalla mia simulazione del monte carlo in C#. Non ho familiarità con c/C++ come compilare i loro src e come usarli da C#. – m3ntat

0

C'è un motivo per cui non è possibile compilare l'implementazione C in una DLL e chiamarla dal codice C#?

EDIT:

Mi dispiace, ma ho solo una conoscenza molto limitata della C (e in effetti C#), ma il "Come creare una DLL C" si può rispondere qui: http://www.kapilik.com/2007/09/17/how-to-create-a-simple-win32-dll-using-visual-c-2005/ e quanto velocemente può essere controllato profilando il codice.

+0

Ciao Patrick, non ho mai usato c, non sono sicuro di come farlo? e uso da C#, sono probabilmente in grado di perdere molte prestazioni vinte da quello che presumo. Net esegue un pacchettizzazione delle mie chiamate da C# alla DLL c sottostante? – m3ntat

+0

Direi che P/Invoke ripetutamente in codice non gestito comporta un sovraccarico di prestazioni piuttosto pesante. – Joey

+0

Ho appena scoperto questo: http://www.codeproject.com/KB/DLL/SFMT_dll.aspx?msg=3130186 mi chiedo se potrebbe rivelarsi utile per la mia situazione – m3ntat

0

Forse this è quello che stai cercando? C'è una lista di diverse implementazioni.

In particolare, this one (di Cory Nelson) potrebbe essere utile.

Problemi correlati