적절한 벤치마킹을 해보 죠. 셔플이 shuffle1
으로 바뀌었고, 개인적으로 좋아하는 변종이 shuffle2
으로 바뀌 었습니다.
[email protected]:~/hask$ ghc -O2 shuffle.hs
[1 of 1] Compiling Main (shuffle.hs, shuffle.o)
Linking shuffle ...
[email protected]:~/hask$ ./shuffle
(1 1,[0, .. <redacted for brevity>])
warming up
estimating clock resolution...
mean is 5.762060 us (160001 iterations)
found 4887 outliers among 159999 samples (3.1%)
4751 (3.0%) high severe
estimating cost of a clock call...
mean is 42.13314 ns (43 iterations)
benchmarking shuffle1
mean: 10.95922 ms, lb 10.92317 ms, ub 10.99903 ms, ci 0.950
std dev: 193.8795 us, lb 168.6842 us, ub 244.6648 us, ci 0.950
found 1 outliers among 100 samples (1.0%)
variance introduced by outliers: 10.396%
variance is moderately inflated by outliers
benchmarking shuffle2
mean: 256.9394 us, lb 255.5414 us, ub 258.7409 us, ci 0.950
std dev: 8.042766 us, lb 6.460785 us, ub 12.28447 us, ci 0.950
found 1 outliers among 100 samples (1.0%)
1 (1.0%) high severe
variance introduced by outliers: 26.750%
variance is moderately inflated by outliers
좋아, 내 시스템이 정말 시끄러운이며, 비슷한 숫자 가지의 심각한 벤치마킹을 위해 사용할 수 없습니다 :
import System.Random
import Control.Monad
import Control.Monad.ST.Strict
import Data.STRef.Strict
import Data.Vector.Mutable
import Prelude as P
import Criterion.Main
shuffle1 :: RandomGen g => [a] -> g -> ([a], g)
shuffle1 [] g0 = ([],g0)
shuffle1 [x] g0 = ([x],g0)
shuffle1 xs g0 = (x:newtail,g2)
where (i,g1) = randomR (0, P.length $ P.tail xs) g0
(xs1,x:xs2) = P.splitAt i xs
(newtail,g2) = shuffle1 (xs1++xs2) g1
shuffle2 :: RandomGen g => [a] -> g -> ([a], g)
shuffle2 xs g0 = runST $ do
let l = P.length xs
v <- new l
sequence_ $ zipWith (unsafeWrite v) [0..] xs
let loop g i | i <= 1 = return g
| otherwise = do
let i' = i - 1
(j, g') = randomR (0, i') g
unsafeSwap v i' j
loop g' i'
gFinal <- loop g0 l
shuffled <- mapM (unsafeRead v) [0 .. l - 1]
return (shuffled, gFinal)
main = do
let s1 x = fst $ shuffle1 x g0
s2 x = fst $ shuffle2 x g0
arr = [0..1000] :: [Int]
g0 = mkStdGen 0
-- make sure these values are evaluated before the benchmark starts
print (g0, arr)
defaultMain [bench "shuffle1" $ nf s1 arr, bench "shuffle2" $ nf s2 arr]
그래서,의 몇 가지 결과를 볼 수 있습니다. 하지만 여기에서는 거의 중요하지 않습니다. shuffle2
은 1001 개의 요소가있는 목록에서 shuffle1
보다 약 40 배 빠릅니다. O (n)과 O (n^2)의 차이로 인해 더 큰 목록에서만 증가합니다. 나는 당신의 테스트 코드가 타이밍에 관계없이, 셔플 알고리즘이 아니라고 확신한다.
사실 나는 추측합니다. 귀하의 버전은 결과를 점진적으로 반환 할만큼 게으른 것입니다. 발전기를 호출 한 후 발전기를 만지지 않는다면 5 초가 처음 몇 가지 결과를 얻는 데 유력한 시간입니다. 어쩌면 그것은 당신의 타이밍에서 일어나는 일일 것입니다.
모든 반복에서 목록의 길이가 계산된다는 것을 감안할 때, 지정한 실적 번호는 믿기 어렵다. 그것은 O (n^2) 알고리즘입니다. – Carl
실제로 전체 결과를 평가하지 않고 알고리즘 타이밍을 잡을 예정입니까? –
타이밍 코드를 표시하십시오. 이 코드를 사용하는 3 천만의'Int's가 완료되기까지 며칠이 걸립니다. –