2014-09-24 17 views
5

Ich mache Monte-Carlo-Simulationen und derzeit System.Random.Schnellste Möglichkeit, eine Milliarde zufällige Doppel in Haskell zu generieren

import System.Random 
main = do 
    g <- newStdGen 
    let xs = randoms g :: [Double] 
    -- normally, I'd do other magic here 
    putStrLn $ show $ length $ take 10^9 xs 

Leider dauert dies eine wirklich lange Zeit, mindestens 5-mal langsamer als Python random.random(), ganz zu schweigen von dem C rand() Anruf.

Mit ghc -O2 -optc-ffast-math -optc-O3

import System.Random 
main = do 
    g <- newStdGen 
    let xs = randoms h :: [Double] 
    putStrLn $ show $ length $ take (10^7) xs 

nimmt ~ 8s gegen (in ipython)

import random 
%timeit len([random.random() for _ in range(10 ** 7)]) 

nimmt ~ 1,3 s. Mein Ziel ist eine Milliarde, aber Haskell kann sie nicht in angemessener Zeit generieren.

Ich habe auch ein C++ - Programm, das Floats mit rand() generiert. Es tut 10^7 Proben in 0,2 Sekunden.

Wie kann ich in Haskell schnell Zufallsdoppelwerte im Bereich [0-1) erzeugen?

Idealerweise wird das Programm, das GHC generiert, nur rand() POSIX-Aufrufe senden und in einer Liste sammeln. Die Antwort mit dem saubersten & schnellsten Code gewinnt. (Nein, 10x der Code für 1% Beschleunigung ist es nicht wert.)

+3

Check out [System.Random.MWC] (http://hackage.haskell.org/package/mwc-random) – ErikR

+0

@ user5402 Mit MWC Beispiel 'withSystemRandom. asGenST $ \ gen -> uniformVector gen (10^7) 'Um einen' Vektor' (der effizienter sein sollte) von 10 Millionen Doubles zu erzeugen, dauerte es ungefähr 15 Sekunden auf meinem Computer, während 'System.Random.randoms' verwendet wurde dauerte nur 12,5 Sekunden. Sind Sie sicher, dass dies die Generation wirklich beschleunigen wird? – bheklilr

+0

Dies kann Ihnen helfen: http://stackoverflow.com/questions/4577146/good-choice-for-fast-random-generator-in-haskell – Sibi

Antwort

2

Hier ist Mersenne, die überraschend schien schneller als MWC und schlägt C++, obwohl wir auf verschiedenen Computern sind ;-). Es ist verlockend zu sehen, wie viel Parallelisierung es kaufen würde, aber ich gehe besser zur Arbeit zurück.

{-# LANGUAGE BangPatterns #-} 
{-# OPTIONS_GHC -Wall      #-} 
{-# OPTIONS_GHC -fno-warn-name-shadowing #-} 
{-# OPTIONS_GHC -fno-warn-type-defaults #-} 

import System.Random.Mersenne.Pure64 

testUniform :: Int -> Double -> PureMT -> Double 
testUniform 0 !x _ = x 
testUniform n !x gen = 
    testUniform (n - 1) (x + y) gen' 
    where 
    (y, gen') = randomDouble gen 

n :: Int 
n = 10^7 

total :: Double 
total = testUniform n 0 (pureMT $ fromIntegral arbSeed) 

arbSeed :: Int 
arbSeed = 8 

mean :: Double 
mean = total/fromIntegral n 

main :: IO() 
main = print mean 

~/Dropbox/Private/Stochastic $ ./MersennePure +RTS -s 
0.4999607889729769 
    802,924,992 bytes allocated in the heap 
     164,240 bytes copied during GC 
      44,312 bytes maximum residency (2 sample(s)) 
      21,224 bytes maximum slop 
       1 MB total memory in use (0 MB lost due to fragmentation) 

            Tot time (elapsed) Avg pause Max pause 
    Gen 0  1634 colls,  0 par 0.00s 0.01s  0.0000s 0.0000s 
    Gen 1   2 colls,  0 par 0.00s 0.00s  0.0001s 0.0002s 

    INIT time 0.00s ( 0.00s elapsed) 
    MUT  time 0.11s ( 0.11s elapsed) 
    GC  time 0.00s ( 0.01s elapsed) 
    EXIT time 0.00s ( 0.00s elapsed) 
    Total time 0.12s ( 0.12s elapsed) 

    %GC  time  4.2% (5.4% elapsed) 

    Alloc rate 7,336,065,126 bytes per MUT second 

    Productivity 95.7% of total user, 93.5% of total elapsed 
+0

Ich bin mir nicht sicher, ob dies mehr oder weniger wie PythonNuts Anwendungsfall ist, aber es ist erwähnenswert, dass Sie erheblich sparen, indem Sie die Konstruktion vermeiden und dann eine große Liste durchlaufen. –

+0

Entschuldigung, ich kann momentan keine Pakete installieren, daher kann ich nicht antworten ... :( – PythonNut

+0

@ ThomasM.DuBuisson würde Stream Fusion nicht annullieren, dass Overhead? – PythonNut

Verwandte Themen