Created
May 3, 2018 05:29
-
-
Save sighingnow/fdc38489e4eab6dabb2b1c39f079cefe to your computer and use it in GitHub Desktop.
Benchmark on several implementations of `numericEnumFromThen` and `numericEnumFromThenTo`.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{-# LANGUAGE BangPatterns #-} | |
import Criterion.Main | |
import Weigh | |
numericEnumFromThen :: (Fractional a) => a -> a -> [a] | |
numericEnumFromThen n m = n `seq` m `seq` (n : numericEnumFromThen m (m+m-n)) | |
numericEnumFromThenTo :: (Ord a, Fractional a) => a -> a -> a -> [a] | |
numericEnumFromThenTo e1 e2 e3 | |
= takeWhile predicate (numericEnumFromThen e1 e2) | |
where | |
mid = (e2 - e1) / 2 | |
predicate | e2 >= e1 = (<= e3 + mid) | |
| otherwise = (>= e3 + mid) | |
------------------------------------------------------------------------------- | |
numericEnumFromThen' :: (Fractional a) => a -> a -> [a] | |
numericEnumFromThen' n m = go 0 | |
where | |
step = m - n | |
go !k = let n' = n + k * step | |
in n' `seq` (n' : go (k + 1)) | |
numericEnumFromThenTo' :: (Ord a, Fractional a) => a -> a -> a -> [a] | |
numericEnumFromThenTo' e1 e2 e3 | |
= takeWhile predicate (numericEnumFromThen' e1 e2) | |
where | |
mid = (e2 - e1) / 2 | |
predicate | e2 >= e1 = (<= e3 + mid) | |
| otherwise = (>= e3 + mid) | |
------------------------------------------------------------------------------- | |
numericEnumFromThen'' :: (Fractional a) => a -> a -> [a] | |
numericEnumFromThen'' n m = go 0 | |
where | |
step = m - n | |
-- See Note [Numeric Stability of Enumerating Floating Numbers] | |
go !k = let !n' = n + k * step | |
in n' `seq` (n' : go (k + 1)) | |
numericEnumFromThenTo'' :: (Ord a, Fractional a) => a -> a -> a -> [a] | |
numericEnumFromThenTo'' e1 e2 e3 | |
= takeWhile predicate (numericEnumFromThen'' e1 e2) | |
where | |
mid = (e2 - e1) / 2 | |
predicate | e2 >= e1 = (<= e3 + mid) | |
| otherwise = (>= e3 + mid) | |
-------------------------------------------------------------------------------- | |
numericEnumFromThen''' :: (Fractional a) => a -> a -> [a] | |
numericEnumFromThen''' n m = go 0 (m - n) | |
where | |
-- See Note [Numeric Stability of Enumerating Floating Numbers] | |
go !k !step = let n' = n + k * step | |
in n' `seq` (n' : go (k + 1) step) | |
numericEnumFromThenTo''' :: (Ord a, Fractional a) => a -> a -> a -> [a] | |
numericEnumFromThenTo''' e1 e2 e3 | |
= takeWhile predicate (numericEnumFromThen''' e1 e2) | |
where | |
mid = (e2 - e1) / 2 | |
predicate | e2 >= e1 = (<= e3 + mid) | |
| otherwise = (>= e3 + mid) | |
-------------------------------------------------------------------------------- | |
numericEnumFromThen'''' :: (Fractional a) => a -> a -> [a] | |
numericEnumFromThen'''' n m = go 0 (m - n) | |
where | |
-- See Note [Numeric Stability of Enumerating Floating Numbers] | |
go !k !step = let !n' = n + k * step | |
in n' `seq` (n' : go (k + 1) step) | |
numericEnumFromThenTo'''' :: (Ord a, Fractional a) => a -> a -> a -> [a] | |
numericEnumFromThenTo'''' e1 e2 e3 | |
= takeWhile predicate (numericEnumFromThen'''' e1 e2) | |
where | |
mid = (e2 - e1) / 2 | |
predicate | e2 >= e1 = (<= e3 + mid) | |
| otherwise = (>= e3 + mid) | |
-------------------------------------------------------------------------------- | |
-- norm :: [Double] -> Double | |
-- norm = sqrt . sum . map (\x -> x*x) | |
-- -- main :: IO () | |
-- -- main = do | |
-- -- print (norm (numericEnumFromThenTo''' 0 1 10000000) > 100) | |
-- -- -- print (norm (numericEnumFromThenTo' 0 1 10000000) > 100) | |
main :: IO () | |
main = benchTime | |
-- main = benchMem | |
benchTime :: IO () | |
benchTime = defaultMain [ | |
bgroup "enum" [ | |
bench "step-in-where" $ whnf (sum . numericEnumFromThenTo' 0 1) (10000000 :: Double) | |
, bench "step-in-where-bang-let" $ whnf (sum . numericEnumFromThenTo'' 0 1) (10000000 :: Double) | |
, bench "step-pass-around" $ whnf (sum . numericEnumFromThenTo''' 0 1) (10000000 :: Double) | |
, bench "step-pass-around-bang-let" $ whnf (sum . numericEnumFromThenTo'''' 0 1) (10000000 :: Double) | |
, bench "original-version" $ whnf (sum . numericEnumFromThenTo 0 1) (10000000 :: Double) | |
] | |
] | |
benchMem :: IO () | |
benchMem = mainWith $ do | |
func "step-in-where" (sum . numericEnumFromThenTo' 0 1) (10000000 :: Double) | |
func "step-in-where-bang-let" (sum . numericEnumFromThenTo'' 0 1) (10000000 :: Double) | |
func "step-pass-around" (sum . numericEnumFromThenTo''' 0 1) (10000000 :: Double) | |
func "step-pass-around-bang-let" (sum . numericEnumFromThenTo'''' 0 1) (10000000 :: Double) | |
func "original-version" (sum . numericEnumFromThenTo 0 1) (10000000 :: Double) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Case Allocated GCs | |
step-in-where 640,000,200 610 | |
step-in-where-bang-let 640,000,200 610 | |
step-pass-around 720,000,216 691 | |
step-pass-around-bang-let 720,000,216 691 | |
original-version 720,000,216 691 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
benchmarking enum/step-in-where | |
time 50.38 ms (50.00 ms .. 50.75 ms) | |
1.000 R² (1.000 R² .. 1.000 R²) | |
mean 50.90 ms (50.65 ms .. 51.53 ms) | |
std dev 532.0 us (180.1 us .. 792.3 us) | |
variance introduced by outliers: 11% (moderately inflated) | |
benchmarking enum/step-in-where-bang-let | |
time 43.10 ms (41.89 ms .. 44.46 ms) | |
0.998 R² (0.994 R² .. 1.000 R²) | |
mean 43.60 ms (43.20 ms .. 44.57 ms) | |
std dev 927.7 us (294.4 us .. 1.541 ms) | |
benchmarking enum/step-pass-around | |
time 45.99 ms (45.51 ms .. 46.66 ms) | |
1.000 R² (0.999 R² .. 1.000 R²) | |
mean 46.53 ms (46.20 ms .. 47.25 ms) | |
std dev 711.8 us (256.3 us .. 1.100 ms) | |
variance introduced by outliers: 11% (moderately inflated) | |
benchmarking enum/step-pass-around-bang-let | |
time 43.59 ms (43.07 ms .. 44.33 ms) | |
1.000 R² (0.999 R² .. 1.000 R²) | |
mean 43.56 ms (43.32 ms .. 43.79 ms) | |
std dev 371.4 us (249.2 us .. 617.4 us) | |
benchmarking enum/original-version | |
time 42.78 ms (42.09 ms .. 43.17 ms) | |
1.000 R² (0.999 R² .. 1.000 R²) | |
mean 43.22 ms (42.92 ms .. 43.61 ms) | |
std dev 520.9 us (356.3 us .. 692.5 us) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment