Skip to content

Instantly share code, notes, and snippets.

@guibou
Last active March 10, 2020 22:48
Show Gist options
  • Select an option

  • Save guibou/21da76d19577e56da54303a6be7c82ce to your computer and use it in GitHub Desktop.

Select an option

Save guibou/21da76d19577e56da54303a6be7c82ce to your computer and use it in GitHub Desktop.
Experimenting a `SafeInt` wrapper for Int which triggers exception when overflow / underflow.
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
import Criterion.Main
newtype SafeInt t = SafeInt t
deriving (Show, Ord, Eq)
instance (Bounded t, Num t, Integral t) => Num (SafeInt t) where
(+) (SafeInt a) (SafeInt b)
| maxBound - a >= b = SafeInt (a + b)
| otherwise = error "overflow"
(-) (SafeInt a) (SafeInt b)
| a >= b = SafeInt (a - b)
| otherwise = error "underflow"
(*) (SafeInt a) (SafeInt b)
| maxBound `div` a >= b = SafeInt (a * b)
| otherwise = error "overflow"
negate _ = error "Could not negate a SafeInt. Num sucks"
abs x = x
signum _ = 1
fromInteger i
| i < 0 = error "underflow"
| i > fromIntegral (maxBound :: t) = error "overflow"
| otherwise = SafeInt (fromInteger i)
-- The function we're benchmarking.
-- with multiplication (test includes a div, so it is slow)
foo :: (Ord t, Num t) => t -> t
foo x = go x 1
where
go x !acc
| x == 0 = acc
| x < 10 = go (x - 1) (acc + 1)
| x >= 10 = go (x - 2) (acc * 2)
-- Without multiplication, no div, supposed fast
bar :: (Ord t, Num t) => t -> t
bar x = go x 1
where
go x !acc
| x == 0 = acc
| x < 10 = go (x - 1) (acc + 1)
| x >= 10 = go (x - 2) (acc + 2)
-- Our benchmark harness.
main = defaultMain [
bgroup "foo" [ bench "@Int" $ whnf (foo @Int) 100
, bench "@(SafeInt Int)" $ whnf (foo @(SafeInt Int)) 100
],
bgroup "bar" [ bench "@Int" $ whnf (bar @Int) 100
, bench "@(SafeInt Int)" $ whnf (bar @(SafeInt Int)) 100
]
]
{-
benchmarking foo/@Int
time 39.68 ns (38.83 ns .. 40.80 ns)
0.998 R² (0.996 R² .. 1.000 R²)
mean 39.29 ns (38.96 ns .. 39.85 ns)
std dev 1.412 ns (896.4 ps .. 2.017 ns)
variance introduced by outliers: 57% (severely inflated)
benchmarking foo/@(SafeInt Int)
time 576.2 ns (570.0 ns .. 583.5 ns)
0.999 R² (0.998 R² .. 1.000 R²)
mean 573.7 ns (569.8 ns .. 581.5 ns)
std dev 19.36 ns (12.11 ns .. 32.71 ns)
variance introduced by outliers: 48% (moderately inflated)
benchmarking bar/@Int
time 36.76 ns (36.44 ns .. 37.25 ns)
0.998 R² (0.997 R² .. 1.000 R²)
mean 36.89 ns (36.57 ns .. 37.58 ns)
std dev 1.587 ns (888.9 ps .. 2.385 ns)
variance introduced by outliers: 66% (severely inflated)
benchmarking bar/@(SafeInt Int)
time 91.43 ns (90.18 ns .. 92.87 ns)
0.999 R² (0.998 R² .. 1.000 R²)
mean 91.25 ns (90.64 ns .. 92.28 ns)
std dev 2.624 ns (1.699 ns .. 3.777 ns)
variance introduced by outliers: 44% (moderately inflated)
-}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment