Skip to content

Commit

Permalink
Improve performance of Integer range generation
Browse files Browse the repository at this point in the history
  • Loading branch information
lehins committed Apr 21, 2020
1 parent 61628e4 commit 4055a8e
Showing 1 changed file with 12 additions and 9 deletions.
21 changes: 12 additions & 9 deletions System/Random/Internal.hs
Original file line number Diff line number Diff line change
Expand Up @@ -737,19 +737,22 @@ randomIvalInteger (l,h) rng
-- | Generate an 'Integer' in the range @[l, h]@ if @l <= h@ and @[h, l]@
-- otherwise.
uniformIntegerM :: (MonadRandom g s m) => (Integer, Integer) -> g s -> m Integer
uniformIntegerM (l, h) gen = case l `compare` h of
LT -> do
let limit = h - l
let limitAsWord64 :: Word64 = fromIntegral limit
uniformIntegerM (l, h) gen
| l == h = pure l
| otherwise = do
let (limit, low) =
if l < h
then (h - l, l)
else (l - h, h)
limitAsWord64 :: Word64 = fromIntegral limit
bounded <-
if (toInteger limitAsWord64) == limit
if toInteger limitAsWord64 == limit
-- Optimisation: if 'limit' fits into 'Word64', generate a bounded
-- 'Word64' and then convert to 'Integer'
then toInteger <$> unsignedBitmaskWithRejectionM uniformWord64 limitAsWord64 gen
then toInteger <$>
unsignedBitmaskWithRejectionM uniformWord64 limitAsWord64 gen
else boundedExclusiveIntegerM (limit + 1) gen
return $ l + bounded
GT -> uniformIntegerM (h, l) gen
EQ -> pure l
return $ low + bounded
{-# INLINE uniformIntegerM #-}

-- | Generate an 'Integer' in the range @[0, s)@ using a variant of Lemire's
Expand Down

0 comments on commit 4055a8e

Please sign in to comment.