Last active
March 10, 2020 22:48
-
-
Save guibou/21da76d19577e56da54303a6be7c82ce to your computer and use it in GitHub Desktop.
Experimenting a `SafeInt` wrapper for Int which triggers exception when overflow / underflow.
This file contains hidden or 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 #-} | |
| {-# 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