performance - 在 Haskell 中生成十亿个随机 double 的最快方法

标签 performance haskell random

我正在做蒙特卡罗模拟,目前正在使用 System.Random .

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

不幸的是,这需要很长时间,至少比 Python 的 random.random() 慢 5 倍。 ,更不用说 C rand()称呼。

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

需要 ~8s 与(在 iPython 中)
import random
%timeit len([random.random() for _ in range(10 ** 7)])

需要约 1.3 秒。我的目标是 10 亿,但是 Haskell 无法在合理的时间内生成它们。

我还有一个 C++ 程序,它用 rand() 生成浮点数。 .确实如此 10^7 0.2 秒内采样。

如何生成范围内的随机 double [0-1)在 Haskell 中快速?

理想情况下,GHC 生成的程序会爆炸 rand() POSIX 调用并收集到列表中。使用最干净和最快的代码的答案获胜。 (不,将 10 倍的代码用于 1% 的加速是不值得的。)

最佳答案

这是 Mersenne,虽然我们在不同的计算机上,但它出人意料地似乎比 MWC 更快并且击败了 C++ ;-)。很想知道它会购买多少并行化,但我最好回去工作。

{-# 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

关于performance - 在 Haskell 中生成十亿个随机 double 的最快方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26024405/

相关文章:

c# - 如何使此 LINQ 查询更快?

sql - 查询优化 - VARCHAR 相等与数字相等

haskell - 检查给定的 Integer 是否是元组列表中元组的第一个元素

haskell - Haskell 类型类中的记录选择器

java - 是否有一个随机函数可以返回所选类型的值?

sql - 检查 Date 是否为 NULL 或与 1/0 进行比较是否更快?

haskell - 在 Haskell 中阅读 GraphML

java - 计算前一个循环的平均值 - Java

java - 如何使用 onClick for android 从按钮生成随机类结果?

C# 到 C++ 多线程,会出现什么问题?