Copyright | (c) The University of Glasgow 2001 |
---|---|
License | BSD-style (see the file LICENSE in the 'random' repository) |
Maintainer | libraries@haskell.org |
Stability | stable |
Safe Haskell | Trustworthy |
Language | Haskell2010 |
This library deals with the common task of pseudo-random number generation.
Synopsis
- class RandomGen g where
- next :: g -> (Int, g)
- genWord8 :: g -> (Word8, g)
- genWord16 :: g -> (Word16, g)
- genWord32 :: g -> (Word32, g)
- genWord64 :: g -> (Word64, g)
- genWord32R :: Word32 -> g -> (Word32, g)
- genWord64R :: Word64 -> g -> (Word64, g)
- genShortByteString :: Int -> g -> (ShortByteString, g)
- unsafeUniformFillMutableByteArray :: MutableByteArray s -> Int -> Int -> g -> ST s g
- genRange :: g -> (Int, Int)
- split :: g -> (g, g)
- class RandomGen g => SplitGen g where
- splitGen :: g -> (g, g)
- class Random a where
- class Uniform a
- class UniformRange a
- class Finite a
- data Seed g
- data StdGen
- class (KnownNat (SeedSize g), 1 <= SeedSize g, Typeable g) => SeedGen g where
- uniform :: (Uniform a, RandomGen g) => g -> (a, g)
- uniformR :: (UniformRange a, RandomGen g) => (a, a) -> g -> (a, g)
- uniforms :: (Uniform a, RandomGen g) => g -> [a]
- uniformRs :: (UniformRange a, RandomGen g) => (a, a) -> g -> [a]
- uniformList :: (Uniform a, RandomGen g) => Int -> g -> ([a], g)
- uniformListR :: (UniformRange a, RandomGen g) => Int -> (a, a) -> g -> ([a], g)
- uniformShuffleList :: RandomGen g => [a] -> g -> ([a], g)
- uniformByteArray :: RandomGen g => Bool -> Int -> g -> (ByteArray, g)
- uniformByteString :: RandomGen g => Int -> g -> (ByteString, g)
- uniformFillMutableByteArray :: RandomGen g => MutableByteArray s -> Int -> Int -> g -> ST s g
- genByteString :: RandomGen g => Int -> g -> (ByteString, g)
- mkStdGen :: Int -> StdGen
- mkStdGen64 :: Word64 -> StdGen
- initStdGen :: MonadIO m => m StdGen
- getStdRandom :: MonadIO m => (StdGen -> (a, StdGen)) -> m a
- getStdGen :: MonadIO m => m StdGen
- setStdGen :: MonadIO m => StdGen -> m ()
- newStdGen :: MonadIO m => m StdGen
- randomIO :: (Random a, MonadIO m) => m a
- randomRIO :: (Random a, MonadIO m) => (a, a) -> m a
- seedSize :: forall g. SeedGen g => Int
- seedSizeProxy :: forall proxy g. SeedGen g => proxy g -> Int
- mkSeed :: forall g m. (SeedGen g, MonadFail m) => ByteArray -> m (Seed g)
- unSeed :: Seed g -> ByteArray
- mkSeedFromByteString :: (SeedGen g, MonadFail m) => ByteString -> m (Seed g)
- unSeedToByteString :: Seed g -> ByteString
- withSeed :: SeedGen g => Seed g -> (g -> (a, g)) -> (a, Seed g)
- withSeedM :: (SeedGen g, Functor f) => Seed g -> (g -> f (a, g)) -> f (a, Seed g)
- withSeedFile :: (SeedGen g, MonadIO m) => FilePath -> (Seed g -> m (a, Seed g)) -> m a
- seedGenTypeName :: forall g. SeedGen g => String
- nonEmptyToSeed :: forall g. SeedGen g => NonEmpty Word64 -> Seed g
- nonEmptyFromSeed :: forall g. SeedGen g => Seed g -> NonEmpty Word64
- class Monad m => StatefulGen g m where
- uniformWord32R :: Word32 -> g -> m Word32
- uniformWord64R :: Word64 -> g -> m Word64
- uniformWord8 :: g -> m Word8
- uniformWord16 :: g -> m Word16
- uniformWord32 :: g -> m Word32
- uniformWord64 :: g -> m Word64
- uniformShortByteString :: Int -> g -> m ShortByteString
- class StatefulGen (MutableGen f m) m => FrozenGen f m where
- type MutableGen f m = (g :: Type) | g -> f
- freezeGen :: MutableGen f m -> m f
- modifyGen :: MutableGen f m -> (f -> (a, f)) -> m a
- overwriteGen :: MutableGen f m -> f -> m ()
- class FrozenGen f m => ThawedGen f m where
- thawGen :: f -> m (MutableGen f m)
- withMutableGen :: ThawedGen f m => f -> (MutableGen f m -> m a) -> m (a, f)
- withMutableGen_ :: ThawedGen f m => f -> (MutableGen f m -> m a) -> m a
- withSeedMutableGen :: (SeedGen g, ThawedGen g m) => Seed g -> (MutableGen g m -> m a) -> m (a, Seed g)
- withSeedMutableGen_ :: (SeedGen g, ThawedGen g m) => Seed g -> (MutableGen g m -> m a) -> m a
- randomM :: forall a g m. (Random a, RandomGen g, FrozenGen g m) => MutableGen g m -> m a
- randomRM :: forall a g m. (Random a, RandomGen g, FrozenGen g m) => (a, a) -> MutableGen g m -> m a
- splitGenM :: (SplitGen f, FrozenGen f m) => MutableGen f m -> m f
- splitMutableGenM :: (SplitGen f, ThawedGen f m) => MutableGen f m -> m (MutableGen f m)
- class (RandomGen r, StatefulGen g m) => RandomGenM g r m | g -> r where
- applyRandomGenM :: (r -> (a, r)) -> g -> m a
- newtype StateGen g = StateGen {
- unStateGen :: g
- data StateGenM g = StateGenM
- runStateGen :: RandomGen g => g -> (StateGenM g -> State g a) -> (a, g)
- runStateGen_ :: RandomGen g => g -> (StateGenM g -> State g a) -> a
- runStateGenT :: RandomGen g => g -> (StateGenM g -> StateT g m a) -> m (a, g)
- runStateGenT_ :: (RandomGen g, Functor f) => g -> (StateGenM g -> StateT g f a) -> f a
- runStateGenST :: RandomGen g => g -> (forall s. StateGenM g -> StateT g (ST s) a) -> (a, g)
- runStateGenST_ :: RandomGen g => g -> (forall s. StateGenM g -> StateT g (ST s) a) -> a
- newtype AtomicGen g = AtomicGen {
- unAtomicGen :: g
- newtype AtomicGenM g = AtomicGenM {
- unAtomicGenM :: IORef g
- newAtomicGenM :: MonadIO m => g -> m (AtomicGenM g)
- applyAtomicGen :: MonadIO m => (g -> (a, g)) -> AtomicGenM g -> m a
- globalStdGen :: AtomicGenM StdGen
- newtype IOGen g = IOGen {
- unIOGen :: g
- newtype IOGenM g = IOGenM {}
- newIOGenM :: MonadIO m => g -> m (IOGenM g)
- applyIOGen :: MonadIO m => (g -> (a, g)) -> IOGenM g -> m a
- newtype STGen g = STGen {
- unSTGen :: g
- newtype STGenM g s = STGenM {}
- newSTGenM :: g -> ST s (STGenM g s)
- applySTGen :: (g -> (a, g)) -> STGenM g s -> ST s a
- runSTGen :: RandomGen g => g -> (forall s. STGenM g s -> ST s a) -> (a, g)
- runSTGen_ :: RandomGen g => g -> (forall s. STGenM g s -> ST s a) -> a
- newtype TGen g = TGen {
- unTGen :: g
- newtype TGenM g = TGenM {}
- newTGenM :: g -> STM (TGenM g)
- newTGenMIO :: MonadIO m => g -> m (TGenM g)
- applyTGen :: (g -> (a, g)) -> TGenM g -> STM a
- class Uniform a where
- uniformM :: StatefulGen g m => g -> m a
- uniformViaFiniteM :: (StatefulGen g m, Generic a, GFinite (Rep a)) => g -> m a
- class UniformRange a where
- uniformRM :: StatefulGen g m => (a, a) -> g -> m a
- isInRange :: (a, a) -> a -> Bool
- isInRangeOrd :: Ord a => (a, a) -> a -> Bool
- isInRangeEnum :: Enum a => (a, a) -> a -> Bool
- uniformListM :: (StatefulGen g m, Uniform a) => Int -> g -> m [a]
- uniformListRM :: (StatefulGen g m, UniformRange a) => Int -> (a, a) -> g -> m [a]
- uniformShuffleListM :: StatefulGen g m => [a] -> g -> m [a]
- uniformByteArrayM :: StatefulGen g m => Bool -> Int -> g -> m ByteArray
- uniformByteStringM :: StatefulGen g m => Int -> g -> m ByteString
- uniformShortByteStringM :: StatefulGen g m => Int -> g -> m ShortByteString
- fillByteArrayST :: Bool -> Int -> ST s Word64 -> ST s ByteArray
- genShortByteStringIO :: Int -> IO Word64 -> IO ShortByteString
- genShortByteStringST :: Int -> ST s Word64 -> ST s ShortByteString
- defaultUnsafeUniformFillMutableByteArray :: RandomGen g => MutableByteArray s -> Int -> Int -> g -> ST s g
- uniformDouble01M :: forall g m. StatefulGen g m => g -> m Double
- uniformDoublePositive01M :: forall g m. StatefulGen g m => g -> m Double
- uniformFloat01M :: forall g m. StatefulGen g m => g -> m Float
- uniformFloatPositive01M :: forall g m. StatefulGen g m => g -> m Float
- uniformEnumM :: forall a g m. (Enum a, Bounded a, StatefulGen g m) => g -> m a
- uniformEnumRM :: forall a g m. (Enum a, StatefulGen g m) => (a, a) -> g -> m a
- uniformWordR :: StatefulGen g m => Word -> g -> m Word
- scaleFloating :: forall a w. (RealFloat a, Integral w, Bounded w, FiniteBits w) => a -> a -> w -> a
Pure Random Generator
class RandomGen g where Source #
RandomGen
is an interface to pure pseudo-random number generators.
StdGen
is the standard RandomGen
instance provided by this library.
Since: 1.0.0
next :: g -> (Int, g) Source #
Deprecated: No longer used
Returns an Int
that is uniformly distributed over the range returned by
genRange
(including both end points), and a new generator. Using next
is inefficient as all operations go via Integer
. See
here for
more details. It is thus deprecated.
Since: 1.0.0
genWord8 :: g -> (Word8, g) Source #
genWord16 :: g -> (Word16, g) Source #
genWord32 :: g -> (Word32, g) Source #
genWord64 :: g -> (Word64, g) Source #
genWord32R :: Word32 -> g -> (Word32, g) Source #
genWord32R upperBound g
returns a Word32
that is uniformly
distributed over the range [0, upperBound]
.
Since: 1.2.0
genWord64R :: Word64 -> g -> (Word64, g) Source #
genWord64R upperBound g
returns a Word64
that is uniformly
distributed over the range [0, upperBound]
.
Since: 1.2.0
genShortByteString :: Int -> g -> (ShortByteString, g) Source #
Deprecated: In favor of uniformShortByteString
Same as
, but for uniformByteArray
False
ShortByteString
.
genShortByteString n g
returns a ShortByteString
of length n
filled with
pseudo-random bytes.
Note - This function will be removed from the type class in the next major release as
it is no longer needed because of unsafeUniformFillMutableByteArray
.
Since: 1.2.0
unsafeUniformFillMutableByteArray Source #
:: MutableByteArray s | Mutable array to fill with random bytes |
-> Int | Offset into a mutable array from the beginning in number of bytes. Offset must be non-negative, but this will not be checked |
-> Int | Number of randomly generated bytes to write into the array. Number of bytes must be non-negative and less then the total size of the array, minus the offset. This also will be checked. |
-> g | |
-> ST s g |
Fill in the supplied MutableByteArray
with uniformly generated random bytes. This function
is unsafe because it is not required to do any bounds checking. For a safe variant use
uniformFillMutableByteArrayM
instead.
Default type class implementation uses defaultUnsafeUniformFillMutableByteArray
.
Since: 1.3.0
genRange :: g -> (Int, Int) Source #
Deprecated: No longer used
Yields the range of values returned by next
.
It is required that:
- If
(a, b) =
, thengenRange
ga < b
. genRange
must not examine its argument so the value it returns is determined only by the instance ofRandomGen
.
The default definition spans the full range of Int
.
Since: 1.0.0
Deprecated: In favor of splitGen
Returns two distinct pseudo-random number generators.
Implementations should take care to ensure that the resulting generators
are not correlated. Some pseudo-random number generators are not
splittable. In that case, the split
implementation should fail with a
descriptive error
message.
Since: 1.0.0
Instances
class RandomGen g => SplitGen g where Source #
Pseudo-random generators that can be split into two separate and independent psuedo-random generators should provide an instance for this type class.
Historically this functionality was included in the RandomGen
type class in the
split
function, however, few pseudo-random generators possess this property of
splittability. This lead the old split
function being usually implemented in terms of
error
.
Since: 1.3.0
splitGen :: g -> (g, g) Source #
Returns two distinct pseudo-random number generators.
Implementations should take care to ensure that the resulting generators are not correlated.
Since: 1.3.0
The class of types for which random values can be generated. Most
instances of Random
will produce values that are uniformly distributed on the full
range, but for those types without a well-defined "full range" some sensible default
subrange will be selected.
Random
exists primarily for backwards compatibility with version 1.1 of
this library. In new code, use the better specified Uniform
and
UniformRange
instead.
Since: 1.0.0
Nothing
randomR :: RandomGen g => (a, a) -> g -> (a, g) Source #
Takes a range (lo,hi) and a pseudo-random number generator g, and returns a pseudo-random value uniformly distributed over the closed interval [lo,hi], together with a new generator. It is unspecified what happens if lo>hi, but usually the values will simply get swapped.
>>>
let gen = mkStdGen 26
>>>
fst $ randomR ('a', 'z') gen
'z'>>>
fst $ randomR ('a', 'z') gen
'z'
For continuous types there is no requirement that the values lo and hi are ever produced, but they may be, depending on the implementation and the interval.
There is no requirement to follow the Ord
instance and the concept of range can be
defined on per type basis. For example product types will treat their values
independently:
>>>
fst $ randomR (('a', 5.0), ('z', 10.0)) $ mkStdGen 26
('z',5.22694980853051)
In case when a lawful range is desired uniformR
should be used
instead.
Since: 1.0.0
default randomR :: (RandomGen g, UniformRange a) => (a, a) -> g -> (a, g) Source #
random :: RandomGen g => g -> (a, g) Source #
The same as randomR
, but using a default range determined by the type:
- For bounded types (instances of
Bounded
, such asChar
), the range is normally the whole type. - For floating point types, the range is normally the closed interval
[0,1]
. - For
Integer
, the range is (arbitrarily) the range ofInt
.
Since: 1.0.0
randomRs :: RandomGen g => (a, a) -> g -> [a] Source #
Plural variant of randomR
, producing an infinite list of
pseudo-random values instead of returning a new generator.
Since: 1.0.0
randoms :: RandomGen g => g -> [a] Source #
Plural variant of random
, producing an infinite list of
pseudo-random values instead of returning a new generator.
Since: 1.0.0
Instances
Random CBool Source # | |
Random CChar Source # | |
Random CDouble Source # | Note - |
Random CFloat Source # | Note - |
Random CInt Source # | |
Random CIntMax Source # | |
Random CIntPtr Source # | |
Random CLLong Source # | |
Random CLong Source # | |
Random CPtrdiff Source # | |
Random CSChar Source # | |
Random CShort Source # | |
Random CSigAtomic Source # | |
Defined in System.Random randomR :: RandomGen g => (CSigAtomic, CSigAtomic) -> g -> (CSigAtomic, g) Source # random :: RandomGen g => g -> (CSigAtomic, g) Source # randomRs :: RandomGen g => (CSigAtomic, CSigAtomic) -> g -> [CSigAtomic] Source # randoms :: RandomGen g => g -> [CSigAtomic] Source # | |
Random CSize Source # | |
Random CUChar Source # | |
Random CUInt Source # | |
Random CUIntMax Source # | |
Random CUIntPtr Source # | |
Random CULLong Source # | |
Random CULong Source # | |
Random CUShort Source # | |
Random CWchar Source # | |
Random Int16 Source # | |
Random Int32 Source # | |
Random Int64 Source # | |
Random Int8 Source # | |
Random Word16 Source # | |
Random Word32 Source # | |
Random Word64 Source # | |
Random Word8 Source # | |
Random Integer Source # | |
Random Bool Source # | |
Random Char Source # | |
Random Double Source # | Note - |
Random Float Source # | Note - |
Random Int Source # | |
Random Word Source # | |
(Random a, Random b) => Random (a, b) Source # | Note - |
(Random a, Random b, Random c) => Random (a, b, c) Source # | Note - |
(Random a, Random b, Random c, Random d) => Random (a, b, c, d) Source # | Note - |
Defined in System.Random | |
(Random a, Random b, Random c, Random d, Random e) => Random (a, b, c, d, e) Source # | Note - |
(Random a, Random b, Random c, Random d, Random e, Random f) => Random (a, b, c, d, e, f) Source # | Note - |
Defined in System.Random randomR :: RandomGen g => ((a, b, c, d, e, f), (a, b, c, d, e, f)) -> g -> ((a, b, c, d, e, f), g) Source # random :: RandomGen g => g -> ((a, b, c, d, e, f), g) Source # randomRs :: RandomGen g => ((a, b, c, d, e, f), (a, b, c, d, e, f)) -> g -> [(a, b, c, d, e, f)] Source # randoms :: RandomGen g => g -> [(a, b, c, d, e, f)] Source # | |
(Random a, Random b, Random c, Random d, Random e, Random f, Random g) => Random (a, b, c, d, e, f, g) Source # | Note - |
Defined in System.Random randomR :: RandomGen g0 => ((a, b, c, d, e, f, g), (a, b, c, d, e, f, g)) -> g0 -> ((a, b, c, d, e, f, g), g0) Source # random :: RandomGen g0 => g0 -> ((a, b, c, d, e, f, g), g0) Source # randomRs :: RandomGen g0 => ((a, b, c, d, e, f, g), (a, b, c, d, e, f, g)) -> g0 -> [(a, b, c, d, e, f, g)] Source # randoms :: RandomGen g0 => g0 -> [(a, b, c, d, e, f, g)] Source # |
The class of types for which a uniformly distributed value can be drawn from all possible values of the type.
Since: 1.2.0
Instances
class UniformRange a Source #
The class of types for which a uniformly distributed value can be drawn from a range.
Since: 1.2.0
Instances
A type class for data with a finite number of inhabitants. This type class
is used in the default implementation of Uniform
.
Users are not supposed to write instances of Finite
manually.
There is a default implementation in terms of Generic
instead.
>>>
:seti -XDeriveGeneric -XDeriveAnyClass
>>>
import GHC.Generics (Generic)
>>>
data MyBool = MyTrue | MyFalse deriving (Generic, Finite)
>>>
data Action = Code MyBool | Eat (Maybe Bool) | Sleep deriving (Generic, Finite)
Instances
This is a binary form of pseudo-random number generator's state. It is designed to be safe and easy to use for input/output operations like restoring from file, transmitting over the network, etc.
Constructor is not exported, becasue it is important for implementation to enforce the
invariant of the underlying byte array being of the exact same length as the generator has
specified in SeedSize
. Use mkSize
and
unSize
to get access to the raw bytes in a safe manner.
Since: 1.3.0
The standard pseudo-random number generator.
Instances
Show StdGen Source # | |
NFData StdGen Source # | |
Defined in System.Random.Internal | |
Eq StdGen Source # | |
RandomGen StdGen Source # | |
Defined in System.Random.Internal next :: StdGen -> (Int, StdGen) Source # genWord8 :: StdGen -> (Word8, StdGen) Source # genWord16 :: StdGen -> (Word16, StdGen) Source # genWord32 :: StdGen -> (Word32, StdGen) Source # genWord64 :: StdGen -> (Word64, StdGen) Source # genWord32R :: Word32 -> StdGen -> (Word32, StdGen) Source # genWord64R :: Word64 -> StdGen -> (Word64, StdGen) Source # genShortByteString :: Int -> StdGen -> (ShortByteString, StdGen) Source # unsafeUniformFillMutableByteArray :: MutableByteArray s -> Int -> Int -> StdGen -> ST s StdGen Source # | |
SplitGen StdGen Source # | |
SeedGen StdGen Source # | |
type SeedSize StdGen Source # | |
Defined in System.Random.Seed |
class (KnownNat (SeedSize g), 1 <= SeedSize g, Typeable g) => SeedGen g where Source #
Interface for converting a pure pseudo-random number generator to and from non-empty sequence of bytes. Seeds are stored in Little-Endian order regardless of the platform it is being used on, which provides cross-platform compatibility, while providing optimal performance for the most common platform type.
Conversion to and from a Seed
serves as a building block for implementing
serialization for any pure or frozen pseudo-random number generator.
It is not trivial to implement platform independence. For this reason this type class
has two alternative ways of creating an instance for this class. The easiest way for
constructing a platform indepent seed is by converting the inner state of a generator
to and from a list of 64 bit words using toSeed64
and fromSeed64
respectively. In
that case cross-platform support will be handled automaticaly.
>>>
:set -XDataKinds -XTypeFamilies
>>>
import Data.Word (Word8, Word32)
>>>
import Data.Bits ((.|.), shiftR, shiftL)
>>>
import Data.List.NonEmpty (NonEmpty ((:|)))
>>>
data FiveByteGen = FiveByteGen Word8 Word32 deriving Show
>>>
:{
instance SeedGen FiveByteGen where type SeedSize FiveByteGen = 5 fromSeed64 (w64 :| _) = FiveByteGen (fromIntegral (w64 `shiftR` 32)) (fromIntegral w64) toSeed64 (FiveByteGen x1 x4) = let w64 = (fromIntegral x1 `shiftL` 32) .|. fromIntegral x4 in (w64 :| []) :}
>>>
FiveByteGen 0x80 0x01020304
FiveByteGen 128 16909060>>>
fromSeed (toSeed (FiveByteGen 0x80 0x01020304))
FiveByteGen 128 16909060>>>
toSeed (FiveByteGen 0x80 0x01020304)
Seed [0x04, 0x03, 0x02, 0x01, 0x80]>>>
toSeed64 (FiveByteGen 0x80 0x01020304)
549772722948 :| []
However, when performance is of utmost importance or default handling of cross platform
independence is not sufficient, then an adventurous developer can try implementing
conversion into bytes directly with toSeed
and fromSeed
.
Properties that must hold:
> fromSeed (toSeed gen) == gen
> fromSeed64 (toSeed64 gen) == gen
Note, that there is no requirement for every Seed
to roundtrip, eg. this proprty does
not even hold for StdGen
:
>>>
let seed = nonEmptyToSeed (0xab :| [0xff00]) :: Seed StdGen
>>>
seed == toSeed (fromSeed seed)
False
Since: 1.3.0
type SeedSize g :: Nat Source #
Number of bytes that is required for storing the full state of a pseudo-random number generator. It should be big enough to satisfy the roundtrip property:
> fromSeed (toSeed gen) == gen
fromSeed :: Seed g -> g Source #
Convert from a binary representation to a pseudo-random number generator
Since: 1.3.0
toSeed :: g -> Seed g Source #
Convert to a binary representation of a pseudo-random number generator
Since: 1.3.0
fromSeed64 :: NonEmpty Word64 -> g Source #
Construct pseudo-random number generator from a list of words. Whenever list does
not have enough bytes to satisfy the SeedSize
requirement, it will be padded with
zeros. On the other hand when it has more than necessary, extra bytes will be dropped.
For example if SeedSize
is set to 2, then only the lower 16 bits of the first
element in the list will be used.
Since: 1.3.0
toSeed64 :: g -> NonEmpty Word64 Source #
Convert pseudo-random number generator to a list of words
In case when SeedSize
is not a multiple of 8, then the upper bits of the last word
in the list will be set to zero.
Since: 1.3.0
uniform :: (Uniform a, RandomGen g) => g -> (a, g) Source #
Generates a value uniformly distributed over all possible values of that type.
This is a pure version of uniformM
.
Examples
>>>
import System.Random
>>>
let pureGen = mkStdGen 137
>>>
uniform pureGen :: (Bool, StdGen)
(True,StdGen {unStdGen = SMGen 11285859549637045894 7641485672361121627})
You can use type applications to disambiguate the type of the generated numbers:
>>>
:seti -XTypeApplications
>>>
uniform @Bool pureGen
(True,StdGen {unStdGen = SMGen 11285859549637045894 7641485672361121627})
Since: 1.2.0
uniformR :: (UniformRange a, RandomGen g) => (a, a) -> g -> (a, g) Source #
Generates a value uniformly distributed over the provided range, which is interpreted as inclusive in the lower and upper bound.
uniformR (1 :: Int, 4 :: Int)
generates values uniformly from the set \(\{1,2,3,4\}\)uniformR (1 :: Float, 4 :: Float)
generates values uniformly from the set \(\{x\;|\;1 \le x \le 4\}\)
The following law should hold to make the function always defined:
uniformR (a, b) = uniformR (b, a)
This is a pure version of uniformRM
.
Examples
>>>
import System.Random
>>>
let pureGen = mkStdGen 137
>>>
uniformR (1 :: Int, 4 :: Int) pureGen
(4,StdGen {unStdGen = SMGen 11285859549637045894 7641485672361121627})
You can use type applications to disambiguate the type of the generated numbers:
>>>
:seti -XTypeApplications
>>>
uniformR @Int (1, 4) pureGen
(4,StdGen {unStdGen = SMGen 11285859549637045894 7641485672361121627})
Since: 1.2.0
uniforms :: (Uniform a, RandomGen g) => g -> [a] Source #
Produce an infinite list of pseudo-random values. Integrates nicely with list
fusion. Naturally, there is no way to recover the final generator, therefore either use
split
before calling uniforms
or use uniformList
instead.
Similar to randoms
, except it relies on Uniform
type class instead of Random
Examples
>>>
let gen = mkStdGen 2023
>>>
import Data.Word (Word16)
>>>
take 5 $ uniforms gen :: [Word16]
[56342,15850,25292,14347,13919]
Since: 1.3.0
uniformRs :: (UniformRange a, RandomGen g) => (a, a) -> g -> [a] Source #
Produce an infinite list of pseudo-random values in a specified range. Same as
uniforms
, integrates nicely with list fusion. There is no way to recover the final
generator, therefore either use split
before calling uniformRs
or use
uniformListR
instead.
Similar to randomRs
, except it relies on UniformRange
type class instead of
Random
.
Examples
>>>
let gen = mkStdGen 2023
>>>
take 5 $ uniformRs (10, 100) gen :: [Int]
[32,86,21,57,39]
Since: 1.3.0
uniformList :: (Uniform a, RandomGen g) => Int -> g -> ([a], g) Source #
Produce a list of the supplied length with elements generated uniformly.
See uniformListM
for a stateful counterpart.
Examples
>>>
let gen = mkStdGen 2023
>>>
import Data.Word (Word16)
>>>
uniformList 5 gen :: ([Word16], StdGen)
([56342,15850,25292,14347,13919],StdGen {unStdGen = SMGen 6446154349414395371 1920468677557965761})
Since: 1.3.0
uniformListR :: (UniformRange a, RandomGen g) => Int -> (a, a) -> g -> ([a], g) Source #
Produce a list of the supplied length with elements generated uniformly.
See uniformListM
for a stateful counterpart.
Examples
>>>
let gen = mkStdGen 2023
>>>
uniformListR 10 (20, 30) gen :: ([Int], StdGen)
([26,30,27,24,30,25,27,21,27,27],StdGen {unStdGen = SMGen 12965503083958398648 1920468677557965761})
Since: 1.3.0
uniformShuffleList :: RandomGen g => [a] -> g -> ([a], g) Source #
Shuffle elements of a list in a uniformly random order.
Examples
>>>
uniformShuffleList "ELVIS" $ mkStdGen 252
("LIVES",StdGen {unStdGen = SMGen 17676540583805057877 5302934877338729551})
Since: 1.3.0
:: RandomGen g | |
=> Bool | Should byte array be allocted in pinned or unpinned memory. |
-> Int | Number of bytes to generate |
-> g | Pure pseudo-random numer generator |
-> (ByteArray, g) |
Efficiently generates a sequence of pseudo-random bytes in a platform independent manner.
Since: 1.3.0
uniformByteString :: RandomGen g => Int -> g -> (ByteString, g) Source #
Generates a ByteString
of the specified size using a pure pseudo-random
number generator. See uniformByteStringM
for the monadic version.
Examples
>>>
import System.Random
>>>
import Data.ByteString (unpack)
>>>
let pureGen = mkStdGen 137
>>>
unpack . fst $ uniformByteString 10 pureGen
[51,123,251,37,49,167,90,109,1,4]
Since: 1.3.0
uniformFillMutableByteArray Source #
:: RandomGen g | |
=> MutableByteArray s | Mutable array to fill with random bytes |
-> Int | Offset into a mutable array from the beginning in number of bytes. Offset will be clamped into the range between 0 and the total size of the mutable array |
-> Int | Number of randomly generated bytes to write into the array. This number will be clamped between 0 and the total size of the array without the offset. |
-> g | |
-> ST s g |
Fill in a slice of a mutable byte array with randomly generated bytes. This function does not fail, instead it clamps the offset and number of bytes to generate into a valid range.
Since: 1.3.0
genByteString :: RandomGen g => Int -> g -> (ByteString, g) Source #
Deprecated: In favor of uniformByteString
Generates a ByteString
of the specified size using a pure pseudo-random
number generator. See uniformByteStringM
for the monadic version.
Examples
>>>
import System.Random
>>>
import Data.ByteString
>>>
let pureGen = mkStdGen 137
>>>
:seti -Wno-deprecations
>>>
unpack . fst . genByteString 10 $ pureGen
[51,123,251,37,49,167,90,109,1,4]
Since: 1.2.0
mkStdGen :: Int -> StdGen Source #
Constructs a StdGen
deterministically from an Int
seed. See mkStdGen64
for a Word64
variant that is architecture agnostic.
mkStdGen64 :: Word64 -> StdGen Source #
Constructs a StdGen
deterministically from a Word64
seed.
The difference between mkStdGen
is that mkStdGen64
will work the same on 64-bit and
32-bit architectures, while the former can only use 32-bit of information for
initializing the psuedo-random number generator on 32-bit operating systems
Since: 1.3.0
initStdGen :: MonadIO m => m StdGen Source #
Initialize StdGen
using system entropy (i.e. /dev/urandom
) when it is
available, while falling back on using system time as the seed.
Since: 1.2.1
getStdRandom :: MonadIO m => (StdGen -> (a, StdGen)) -> m a Source #
Uses the supplied function to get a value from the current global
random generator, and updates the global generator with the new generator
returned by the function. For example, rollDice
produces a pseudo-random integer
between 1 and 6:
>>>
rollDice = getStdRandom (randomR (1, 6))
>>>
replicateM 10 (rollDice :: IO Int)
[1,1,1,4,5,6,1,2,2,5]
This is an outdated function and it is recommended to switch to its
equivalent applyAtomicGen
instead, possibly with the
globalStdGen
if relying on the global state is
acceptable.
>>>
import System.Random.Stateful
>>>
rollDice = applyAtomicGen (uniformR (1, 6)) globalStdGen
>>>
replicateM 10 (rollDice :: IO Int)
[2,1,1,5,4,3,6,6,3,2]
Since: 1.0.0
getStdGen :: MonadIO m => m StdGen Source #
Gets the global pseudo-random number generator. Extracts the contents of
globalStdGen
Since: 1.0.0
setStdGen :: MonadIO m => StdGen -> m () Source #
Sets the global pseudo-random number generator. Overwrites the contents of
globalStdGen
Since: 1.0.0
newStdGen :: MonadIO m => m StdGen Source #
Applies split
to the current global pseudo-random generator
globalStdGen
, updates it with one of the results,
and returns the other.
Since: 1.0.0
randomIO :: (Random a, MonadIO m) => m a Source #
A variant of randomM
that uses the global
pseudo-random number generator globalStdGen
.
>>>
import Data.Int
>>>
randomIO :: IO Int32
114794456
This function is equivalent to
and is included in
this interface for historical reasons and backwards compatibility. It is
recommended to use getStdRandom
random
uniformM
instead, possibly with
the globalStdGen
if relying on the global state is
acceptable.
>>>
import System.Random.Stateful
>>>
uniformM globalStdGen :: IO Int32
-1768545016
Since: 1.0.0
randomRIO :: (Random a, MonadIO m) => (a, a) -> m a Source #
A variant of randomRM
that uses the global
pseudo-random number generator globalStdGen
>>>
randomRIO (2020, 2100) :: IO Int
2028
Similar to randomIO
, this function is equivalent to
and is included in this interface for historical reasons and
backwards compatibility. It is recommended to use
getStdRandom
randomR
uniformRM
instead, possibly with the
globalStdGen
if relying on the global state is
acceptable.
>>>
import System.Random.Stateful
>>>
uniformRM (2020, 2100) globalStdGen :: IO Int
2044
Since: 1.0.0
seedSize :: forall g. SeedGen g => Int Source #
Get the expected size of the Seed
in number bytes
Since: 1.3.0
seedSizeProxy :: forall proxy g. SeedGen g => proxy g -> Int Source #
Just like seedSize
, except it accepts a proxy as an argument.
Since: 1.3.0
mkSeedFromByteString :: (SeedGen g, MonadFail m) => ByteString -> m (Seed g) Source #
Just like mkSeed
, but uses ByteString
as argument. Results in a memcopy of the seed.
Since: 1.3.0
unSeedToByteString :: Seed g -> ByteString Source #
Just like unSeed
, but produced a ByteString
. Results in a memcopy of the seed.
Since: 1.3.0
withSeed :: SeedGen g => Seed g -> (g -> (a, g)) -> (a, Seed g) Source #
Helper function that allows for operating directly on the Seed
, while supplying a
function that uses the pseudo-random number generator that is constructed from that
Seed
.
Example
>>>
:set -XTypeApplications
>>>
import System.Random
>>>
withSeed (nonEmptyToSeed (pure 2024) :: Seed StdGen) (uniform @Int)
(1039666877624726199,Seed [0xe9, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
Since: 1.3.0
withSeedM :: (SeedGen g, Functor f) => Seed g -> (g -> f (a, g)) -> f (a, Seed g) Source #
Same as withSeed
, except it is useful with monadic computation and frozen generators.
See withSeedMutableGen
for a helper that also handles seeds
for mutable pseduo-random number generators.
Since: 1.3.0
withSeedFile :: (SeedGen g, MonadIO m) => FilePath -> (Seed g -> m (a, Seed g)) -> m a Source #
Read the seed from a file and use it for constructing a pseudo-random number generator. After supplied action has been applied to the constructed generator, the resulting generator will be converted back to a seed and written to the same file.
Since: 1.3.0
seedGenTypeName :: forall g. SeedGen g => String Source #
This is a function that shows the name of the generator type, which is useful for error reporting.
Since: 1.3.0
nonEmptyToSeed :: forall g. SeedGen g => NonEmpty Word64 -> Seed g Source #
Construct a seed from a list of 64-bit words. At most SeedSize
many bytes will be used.
Since: 1.3.0
nonEmptyFromSeed :: forall g. SeedGen g => Seed g -> NonEmpty Word64 Source #
Convert a Seed
to a list of 64bit words.
Since: 1.3.0
Monadic Random Generator
This module provides type classes and instances for the following concepts:
- Monadic pseudo-random number generators
StatefulGen
is an interface to monadic pseudo-random number generators.- Monadic adapters
StateGenM
,AtomicGenM
,IOGenM
,STGenM
andTGenM
turn aRandomGen
instance into aStatefulGen
instance.- Drawing from a range
UniformRange
is used to generate a value of a type uniformly within a range.This library provides instances of
UniformRange
for many common numeric types.- Drawing from the entire domain of a type
Uniform
is used to generate a value of a type uniformly over all possible values of that type.This library provides instances of
Uniform
for many common bounded numeric types.
Usage
In monadic code, use the relevant Uniform
and UniformRange
instances to
generate pseudo-random values via uniformM
and uniformRM
, respectively.
As an example, rollsM
generates n
pseudo-random values of Word
in the range [1,
6]
in a StatefulGen
context; given a monadic pseudo-random number generator, you
can run this probabilistic computation using
mwc-random
as follows:
>>>
import Control.Monad (replicateM)
>>>
:{
let rollsM :: StatefulGen g m => Int -> g -> m [Word] rollsM n = replicateM n . uniformRM (1, 6) :}
import qualified System.Random.MWC as MWC >>> monadicGen <- MWC.create >>> rollsM 10 monadicGen :: IO [Word] [3,4,3,1,4,6,1,6,1,4]
Given a pure pseudo-random number generator, you can run the monadic pseudo-random
number computation rollsM
in StateT
, IO
, ST
or STM
context by applying a monadic adapter like StateGenM
, AtomicGenM
, IOGenM
,
STGenM
or TGenM
(see monadic-adapters) to the pure
pseudo-random number generator.
>>>
let pureGen = mkStdGen 42
>>>
newIOGenM pureGen >>= rollsM 10 :: IO [Word]
[1,1,3,2,4,5,3,4,6,2]
Mutable pseudo-random number generator interfaces
Pseudo-random number generators come in two flavours: pure and monadic.
RandomGen
: pure pseudo-random number generators- See System.Random module.
StatefulGen
: monadic pseudo-random number generators- These generators mutate their
own state as they produce pseudo-random values. They generally live in
StateT
,ST
,IO
orSTM
or some other transformer on top of those monads.
class Monad m => StatefulGen g m where Source #
StatefulGen
is an interface to monadic pseudo-random number generators.
Since: 1.2.0
uniformWord32R :: Word32 -> g -> m Word32 Source #
uniformWord32R upperBound g
generates a Word32
that is uniformly
distributed over the range [0, upperBound]
.
Since: 1.2.0
uniformWord64R :: Word64 -> g -> m Word64 Source #
uniformWord64R upperBound g
generates a Word64
that is uniformly
distributed over the range [0, upperBound]
.
Since: 1.2.0
uniformWord8 :: g -> m Word8 Source #
Generates a Word8
that is uniformly distributed over the entire Word8
range.
The default implementation extracts a Word8
from uniformWord32
.
Since: 1.2.0
uniformWord16 :: g -> m Word16 Source #
Generates a Word16
that is uniformly distributed over the entire
Word16
range.
The default implementation extracts a Word16
from uniformWord32
.
Since: 1.2.0
uniformWord32 :: g -> m Word32 Source #
Generates a Word32
that is uniformly distributed over the entire
Word32
range.
The default implementation extracts a Word32
from uniformWord64
.
Since: 1.2.0
uniformWord64 :: g -> m Word64 Source #
Generates a Word64
that is uniformly distributed over the entire
Word64
range.
The default implementation combines two Word32
from uniformWord32
into
one Word64
.
Since: 1.2.0
uniformShortByteString :: Int -> g -> m ShortByteString Source #
Deprecated: In favor of uniformShortByteStringM
uniformShortByteString n g
generates a ShortByteString
of length n
filled with pseudo-random bytes.
Since: 1.2.0
Instances
class StatefulGen (MutableGen f m) m => FrozenGen f m where Source #
This class is designed for mutable pseudo-random number generators that have a frozen imutable counterpart that can be manipulated in pure code.
It also works great with frozen generators that are based on pure generators that have
a RandomGen
instance.
Here are a few laws, which are important for this type class:
- Roundtrip and complete destruction on overwrite:
overwriteGen mg fg >> freezeGen mg = pure fg
- Modification of a mutable generator:
overwriteGen mg fg = modifyGen mg (const ((), fg)
- Freezing of a mutable generator:
freezeGen mg = modifyGen mg (fg -> (fg, fg))
Since: 1.2.0
type MutableGen f m = (g :: Type) | g -> f Source #
freezeGen :: MutableGen f m -> m f Source #
Saves the state of the pseudo-random number generator as a frozen seed.
Since: 1.2.0
modifyGen :: MutableGen f m -> (f -> (a, f)) -> m a Source #
Apply a pure function to the frozen pseudo-random number generator.
Since: 1.3.0
overwriteGen :: MutableGen f m -> f -> m () Source #
Overwrite contents of the mutable pseudo-random number generator with the supplied frozen one
Since: 1.3.0
Instances
class FrozenGen f m => ThawedGen f m where Source #
Functionality for thawing frozen generators is not part of the FrozenGen
class,
becase not all mutable generators support functionality of creating new mutable
generators, which is what thawing is in its essence. For this reason StateGen
does
not have an instance for this type class, but it has one for FrozenGen
.
Here is an important law that relates this type class to FrozenGen
- Roundtrip and independence of mutable generators:
traverse thawGen fgs >>= traverse freezeGen = pure fgs
Since: 1.3.0
thawGen :: f -> m (MutableGen f m) Source #
Create a new mutable pseudo-random number generator from its frozen state.
Since: 1.2.0
Instances
(RandomGen g, MonadIO m) => ThawedGen (AtomicGen g) m Source # | |
Defined in System.Random.Stateful | |
(RandomGen g, MonadIO m) => ThawedGen (IOGen g) m Source # | |
Defined in System.Random.Stateful | |
RandomGen g => ThawedGen (TGen g) STM Source # | |
Defined in System.Random.Stateful | |
RandomGen g => ThawedGen (STGen g) (ST s) Source # | |
Defined in System.Random.Stateful |
withMutableGen :: ThawedGen f m => f -> (MutableGen f m -> m a) -> m (a, f) Source #
Runs a mutable pseudo-random number generator from its FrozenGen
state.
Examples
>>>
import Data.Int (Int8)
>>>
withMutableGen (IOGen (mkStdGen 217)) (uniformListM 5) :: IO ([Int8], IOGen StdGen)
([-74,37,-50,-2,3],IOGen {unIOGen = StdGen {unStdGen = SMGen 4273268533320920145 15251669095119325999}})
Since: 1.2.0
withMutableGen_ :: ThawedGen f m => f -> (MutableGen f m -> m a) -> m a Source #
Same as withMutableGen
, but only returns the generated value.
Examples
>>>
import System.Random.Stateful
>>>
let pureGen = mkStdGen 137
>>>
withMutableGen_ (IOGen pureGen) (uniformRM (1 :: Int, 6 :: Int))
4
Since: 1.2.0
withSeedMutableGen :: (SeedGen g, ThawedGen g m) => Seed g -> (MutableGen g m -> m a) -> m (a, Seed g) Source #
Just like withMutableGen
, except uses a Seed
instead of a frozen generator.
Examples
Here is good example of how withSeedMutableGen
can be used with withSeedFile
, which uses a locally stored seed.
First we define a reportSeed
function that will print the contents of a seed file as a list of bytes:
>>>
import Data.ByteString as BS (readFile, writeFile, unpack)
>>>
:seti -XOverloadedStrings
>>>
let reportSeed fp = print . ("Seed: " <>) . show . BS.unpack =<< BS.readFile fp
Given a file path, write an StdGen
seed into the file:
>>>
:seti -XFlexibleContexts -XScopedTypeVariables
>>>
let writeInitSeed fp = BS.writeFile fp (unSeedToByteString (toSeed (mkStdGen 2025)))
Apply a StatefulGen
monadic action that uses
, restored from the seed in the given path:IOGen
StdGen
>>>
let withMutableSeedFile fp action = withSeedFile fp (\(seed :: Seed (IOGen StdGen)) -> withSeedMutableGen seed action)
Given a path and an action initialize the seed file and apply the action using that seed:
>>>
let withInitSeedFile fp action = writeInitSeed fp *> reportSeed fp *> withMutableSeedFile fp action <* reportSeed fp
For the sake of example we will use a temporary directory for storing the seed. Here we report the contents of the seed file before and after we shuffle a list:
>>>
import UnliftIO.Temporary (withSystemTempDirectory)
>>>
withSystemTempDirectory "random" (\fp -> withInitSeedFile (fp ++ "/seed.bin") (uniformShuffleListM [1..10]))
"Seed: [183,178,143,77,132,163,109,14,157,105,82,99,148,82,109,173]" "Seed: [60,105,117,203,187,138,69,39,157,105,82,99,148,82,109,173]" [7,5,4,3,1,8,10,6,9,2]
Since: 1.3.0
withSeedMutableGen_ :: (SeedGen g, ThawedGen g m) => Seed g -> (MutableGen g m -> m a) -> m a Source #
Just like withSeedMutableGen
, except it doesn't return the final generator, only
the resulting value. This is slightly more efficient, since it doesn't incur overhead
from freezeing the mutable generator
Since: 1.3.0
randomM :: forall a g m. (Random a, RandomGen g, FrozenGen g m) => MutableGen g m -> m a Source #
Generates a pseudo-random value using monadic interface and Random
instance.
Examples
>>>
import System.Random.Stateful
>>>
let pureGen = mkStdGen 139
>>>
g <- newIOGenM pureGen
>>>
randomM g :: IO Double
0.33775117339631733
You can use type applications to disambiguate the type of the generated numbers:
>>>
:seti -XTypeApplications
>>>
randomM @Double g
0.9156875994165681
Since: 1.2.0
randomRM :: forall a g m. (Random a, RandomGen g, FrozenGen g m) => (a, a) -> MutableGen g m -> m a Source #
Generates a pseudo-random value using monadic interface and Random
instance.
Examples
>>>
import System.Random.Stateful
>>>
let pureGen = mkStdGen 137
>>>
g <- newIOGenM pureGen
>>>
randomRM (1, 100) g :: IO Int
52
You can use type applications to disambiguate the type of the generated numbers:
>>>
:seti -XTypeApplications
>>>
randomRM @Int (1, 100) g
2
Since: 1.2.0
splitGenM :: (SplitGen f, FrozenGen f m) => MutableGen f m -> m f Source #
Splits a pseudo-random number generator into two. Overwrites the mutable
pseudo-random number generator with one of the immutable pseudo-random number
generators produced by a split
function and returns the other.
Since: 1.3.0
splitMutableGenM :: (SplitGen f, ThawedGen f m) => MutableGen f m -> m (MutableGen f m) Source #
Splits a pseudo-random number generator into two. Overwrites the mutable wrapper with one of the resulting generators and returns the other as a new mutable generator.
Since: 1.3.0
Deprecated
class (RandomGen r, StatefulGen g m) => RandomGenM g r m | g -> r where Source #
Deprecated: In favor of FrozenGen
Interface to operations on RandomGen
wrappers like IOGenM
and StateGenM
.
Since: 1.2.0
applyRandomGenM :: (r -> (a, r)) -> g -> m a Source #
Deprecated: In favor of modifyGen
Instances
(RandomGen r, MonadState r m) => RandomGenM (StateGenM r) r m Source # | |
Defined in System.Random.Stateful applyRandomGenM :: (r -> (a, r)) -> StateGenM r -> m a Source # | |
(RandomGen r, MonadIO m) => RandomGenM (AtomicGenM r) r m Source # | |
Defined in System.Random.Stateful applyRandomGenM :: (r -> (a, r)) -> AtomicGenM r -> m a Source # | |
(RandomGen r, MonadIO m) => RandomGenM (IOGenM r) r m Source # | |
Defined in System.Random.Stateful applyRandomGenM :: (r -> (a, r)) -> IOGenM r -> m a Source # | |
RandomGen r => RandomGenM (TGenM r) r STM Source # | |
Defined in System.Random.Stateful applyRandomGenM :: (r -> (a, r)) -> TGenM r -> STM a Source # | |
RandomGen r => RandomGenM (STGenM r s) r (ST s) Source # | |
Defined in System.Random.Stateful applyRandomGenM :: (r -> (a, r)) -> STGenM r s -> ST s a Source # |
Monadic adapters for pure pseudo-random number generators
Pure pseudo-random number generators can be used in monadic code via the
adapters StateGenM
, AtomicGenM
, IOGenM
, STGenM
and TGenM
StateGenM
can be used in any state monad. With strictStateT
there is no performance overhead compared to using theRandomGen
instance directly.StateGenM
is not safe to use in the presence of exceptions and concurrency.AtomicGenM
is safe in the presence of exceptions and concurrency since it performs all actions atomically.IOGenM
is a wrapper around anIORef
that holds a pure generator.IOGenM
is safe in the presence of exceptions, but not concurrency.STGenM
is a wrapper around anSTRef
that holds a pure generator.STGenM
is safe in the presence of exceptions, but not concurrency.TGenM
is a wrapper around aTVar
that holds a pure generator.TGenM
can be used in a software transactional memory monadSTM
. It is not as performant asAtomicGenM
, but it can provide stronger guarantees in a concurrent setting.
Pure adapter in MonadState
Wrapper for pure state gen, which acts as an immutable seed for the corresponding
stateful generator StateGenM
Since: 1.2.0
StateGen | |
|
Instances
Opaque data type that carries the type of a pure pseudo-random number generator.
Since: 1.2.0
Instances
(RandomGen g, MonadState g m) => StatefulGen (StateGenM g) m Source # | |
Defined in System.Random.Internal uniformWord32R :: Word32 -> StateGenM g -> m Word32 Source # uniformWord64R :: Word64 -> StateGenM g -> m Word64 Source # uniformWord8 :: StateGenM g -> m Word8 Source # uniformWord16 :: StateGenM g -> m Word16 Source # uniformWord32 :: StateGenM g -> m Word32 Source # uniformWord64 :: StateGenM g -> m Word64 Source # uniformByteArrayM :: Bool -> Int -> StateGenM g -> m ByteArray Source # uniformShortByteString :: Int -> StateGenM g -> m ShortByteString Source # | |
(RandomGen r, MonadState r m) => RandomGenM (StateGenM r) r m Source # | |
Defined in System.Random.Stateful applyRandomGenM :: (r -> (a, r)) -> StateGenM r -> m a Source # |
runStateGen :: RandomGen g => g -> (StateGenM g -> State g a) -> (a, g) Source #
Runs a monadic generating action in the State
monad using a pure
pseudo-random number generator.
Examples
>>>
import System.Random.Stateful
>>>
let pureGen = mkStdGen 137
>>>
runStateGen pureGen randomM :: (Int, StdGen)
(7879794327570578227,StdGen {unStdGen = SMGen 11285859549637045894 7641485672361121627})
Since: 1.2.0
runStateGen_ :: RandomGen g => g -> (StateGenM g -> State g a) -> a Source #
Runs a monadic generating action in the State
monad using a pure
pseudo-random number generator. Returns only the resulting pseudo-random
value.
Examples
>>>
import System.Random.Stateful
>>>
let pureGen = mkStdGen 137
>>>
runStateGen_ pureGen randomM :: Int
7879794327570578227
Since: 1.2.0
runStateGenT :: RandomGen g => g -> (StateGenM g -> StateT g m a) -> m (a, g) Source #
Runs a monadic generating action in the StateT
monad using a pure
pseudo-random number generator.
Examples
>>>
import System.Random.Stateful
>>>
let pureGen = mkStdGen 137
>>>
runStateGenT pureGen randomM :: IO (Int, StdGen)
(7879794327570578227,StdGen {unStdGen = SMGen 11285859549637045894 7641485672361121627})
Since: 1.2.0
runStateGenT_ :: (RandomGen g, Functor f) => g -> (StateGenM g -> StateT g f a) -> f a Source #
Runs a monadic generating action in the StateT
monad using a pure
pseudo-random number generator. Returns only the resulting pseudo-random
value.
Examples
>>>
import System.Random.Stateful
>>>
let pureGen = mkStdGen 137
>>>
runStateGenT_ pureGen randomM :: IO Int
7879794327570578227
Since: 1.2.1
runStateGenST :: RandomGen g => g -> (forall s. StateGenM g -> StateT g (ST s) a) -> (a, g) Source #
Runs a monadic generating action in the ST
monad using a pure
pseudo-random number generator.
Since: 1.2.0
runStateGenST_ :: RandomGen g => g -> (forall s. StateGenM g -> StateT g (ST s) a) -> a Source #
Runs a monadic generating action in the ST
monad using a pure
pseudo-random number generator. Same as runStateGenST
, but discards the
resulting generator.
Since: 1.2.1
Mutable thread-safe adapter in IO
Frozen version of mutable AtomicGenM
generator
Since: 1.2.0
AtomicGen | |
|
Instances
newtype AtomicGenM g Source #
Wraps an IORef
that holds a pure pseudo-random number generator. All
operations are performed atomically.
AtomicGenM
is safe in the presence of exceptions and concurrency.AtomicGenM
is the slowest of the monadic adapters due to the overhead of its atomic operations.
Since: 1.2.0
AtomicGenM | |
|
Instances
(RandomGen g, MonadIO m) => StatefulGen (AtomicGenM g) m Source # | |
Defined in System.Random.Stateful uniformWord32R :: Word32 -> AtomicGenM g -> m Word32 Source # uniformWord64R :: Word64 -> AtomicGenM g -> m Word64 Source # uniformWord8 :: AtomicGenM g -> m Word8 Source # uniformWord16 :: AtomicGenM g -> m Word16 Source # uniformWord32 :: AtomicGenM g -> m Word32 Source # uniformWord64 :: AtomicGenM g -> m Word64 Source # uniformByteArrayM :: Bool -> Int -> AtomicGenM g -> m ByteArray Source # uniformShortByteString :: Int -> AtomicGenM g -> m ShortByteString Source # | |
(RandomGen r, MonadIO m) => RandomGenM (AtomicGenM r) r m Source # | |
Defined in System.Random.Stateful applyRandomGenM :: (r -> (a, r)) -> AtomicGenM r -> m a Source # |
newAtomicGenM :: MonadIO m => g -> m (AtomicGenM g) Source #
Creates a new AtomicGenM
.
Since: 1.2.0
applyAtomicGen :: MonadIO m => (g -> (a, g)) -> AtomicGenM g -> m a Source #
Atomically applies a pure operation to the wrapped pseudo-random number generator.
Examples
>>>
import System.Random.Stateful
>>>
let pureGen = mkStdGen 137
>>>
g <- newAtomicGenM pureGen
>>>
applyAtomicGen random g :: IO Int
7879794327570578227
Since: 1.2.0
Mutable adapter in IO
Frozen version of mutable IOGenM
generator
Since: 1.2.0
Instances
Wraps an IORef
that holds a pure pseudo-random number generator.
IOGenM
is safe in the presence of exceptions, but not concurrency.IOGenM
is slower thanStateGenM
due to the extra pointer indirection.IOGenM
is faster thanAtomicGenM
since theIORef
operations used byIOGenM
are not atomic.
An example use case is writing pseudo-random bytes into a file:
>>>
import UnliftIO.Temporary (withSystemTempFile)
>>>
import Data.ByteString (hPutStr)
>>>
let ioGen g = withSystemTempFile "foo.bin" $ \_ h -> uniformRM (0, 100) g >>= flip uniformByteStringM g >>= hPutStr h
and then run it:
>>>
newIOGenM (mkStdGen 1729) >>= ioGen
Since: 1.2.0
Instances
(RandomGen g, MonadIO m) => StatefulGen (IOGenM g) m Source # | |
Defined in System.Random.Stateful uniformWord32R :: Word32 -> IOGenM g -> m Word32 Source # uniformWord64R :: Word64 -> IOGenM g -> m Word64 Source # uniformWord8 :: IOGenM g -> m Word8 Source # uniformWord16 :: IOGenM g -> m Word16 Source # uniformWord32 :: IOGenM g -> m Word32 Source # uniformWord64 :: IOGenM g -> m Word64 Source # uniformByteArrayM :: Bool -> Int -> IOGenM g -> m ByteArray Source # uniformShortByteString :: Int -> IOGenM g -> m ShortByteString Source # | |
(RandomGen r, MonadIO m) => RandomGenM (IOGenM r) r m Source # | |
Defined in System.Random.Stateful applyRandomGenM :: (r -> (a, r)) -> IOGenM r -> m a Source # |
applyIOGen :: MonadIO m => (g -> (a, g)) -> IOGenM g -> m a Source #
Applies a pure operation to the wrapped pseudo-random number generator.
Examples
>>>
import System.Random.Stateful
>>>
let pureGen = mkStdGen 137
>>>
g <- newIOGenM pureGen
>>>
applyIOGen random g :: IO Int
7879794327570578227
Since: 1.2.0
Mutable adapter in ST
Frozen version of mutable STGenM
generator
Since: 1.2.0
Instances
Wraps an STRef
that holds a pure pseudo-random number generator.
STGenM
is safe in the presence of exceptions, but not concurrency.STGenM
is slower thanStateGenM
due to the extra pointer indirection.
Since: 1.2.0
Instances
RandomGen r => RandomGenM (STGenM r s) r (ST s) Source # | |
Defined in System.Random.Stateful applyRandomGenM :: (r -> (a, r)) -> STGenM r s -> ST s a Source # | |
RandomGen g => StatefulGen (STGenM g s) (ST s) Source # | |
Defined in System.Random.Stateful uniformWord32R :: Word32 -> STGenM g s -> ST s Word32 Source # uniformWord64R :: Word64 -> STGenM g s -> ST s Word64 Source # uniformWord8 :: STGenM g s -> ST s Word8 Source # uniformWord16 :: STGenM g s -> ST s Word16 Source # uniformWord32 :: STGenM g s -> ST s Word32 Source # uniformWord64 :: STGenM g s -> ST s Word64 Source # uniformByteArrayM :: Bool -> Int -> STGenM g s -> ST s ByteArray Source # uniformShortByteString :: Int -> STGenM g s -> ST s ShortByteString Source # |
applySTGen :: (g -> (a, g)) -> STGenM g s -> ST s a Source #
Applies a pure operation to the wrapped pseudo-random number generator.
Examples
>>>
import System.Random.Stateful
>>>
let pureGen = mkStdGen 137
>>>
(runSTGen pureGen (\g -> applySTGen random g)) :: (Int, StdGen)
(7879794327570578227,StdGen {unStdGen = SMGen 11285859549637045894 7641485672361121627})
Since: 1.2.0
runSTGen :: RandomGen g => g -> (forall s. STGenM g s -> ST s a) -> (a, g) Source #
Runs a monadic generating action in the ST
monad using a pure
pseudo-random number generator.
Examples
>>>
import System.Random.Stateful
>>>
let pureGen = mkStdGen 137
>>>
(runSTGen pureGen (\g -> applySTGen random g)) :: (Int, StdGen)
(7879794327570578227,StdGen {unStdGen = SMGen 11285859549637045894 7641485672361121627})
Since: 1.2.0
runSTGen_ :: RandomGen g => g -> (forall s. STGenM g s -> ST s a) -> a Source #
Runs a monadic generating action in the ST
monad using a pure
pseudo-random number generator. Returns only the resulting pseudo-random
value.
Examples
>>>
import System.Random.Stateful
>>>
let pureGen = mkStdGen 137
>>>
(runSTGen_ pureGen (\g -> applySTGen random g)) :: Int
7879794327570578227
Since: 1.2.0
Mutable thread-safe adapter in STM
Frozen version of mutable TGenM
generator
Since: 1.2.1
Instances
Wraps a TVar
that holds a pure pseudo-random number generator.
Since: 1.2.1
Instances
RandomGen g => StatefulGen (TGenM g) STM Source # | Since: 1.2.1 |
Defined in System.Random.Stateful uniformWord32R :: Word32 -> TGenM g -> STM Word32 Source # uniformWord64R :: Word64 -> TGenM g -> STM Word64 Source # uniformWord8 :: TGenM g -> STM Word8 Source # uniformWord16 :: TGenM g -> STM Word16 Source # uniformWord32 :: TGenM g -> STM Word32 Source # uniformWord64 :: TGenM g -> STM Word64 Source # uniformByteArrayM :: Bool -> Int -> TGenM g -> STM ByteArray Source # uniformShortByteString :: Int -> TGenM g -> STM ShortByteString Source # | |
RandomGen r => RandomGenM (TGenM r) r STM Source # | |
Defined in System.Random.Stateful applyRandomGenM :: (r -> (a, r)) -> TGenM r -> STM a Source # |
applyTGen :: (g -> (a, g)) -> TGenM g -> STM a Source #
Applies a pure operation to the wrapped pseudo-random number generator.
Examples
>>>
import Control.Concurrent.STM
>>>
import System.Random.Stateful
>>>
import Data.Int (Int32)
>>>
let pureGen = mkStdGen 137
>>>
stmGen <- newTGenMIO pureGen
>>>
atomically $ applyTGen uniform stmGen :: IO Int32
637238067
Since: 1.2.1
Pseudo-random values of various types
This library provides two type classes to generate pseudo-random values:
UniformRange
is used to generate a value of a type uniformly within a range.Uniform
is used to generate a value of a type uniformly over all possible values of that type.
Types may have instances for both or just one of UniformRange
and
Uniform
. A few examples illustrate this:
Int
,Word16
andBool
are instances of bothUniformRange
andUniform
.Integer
,Float
andDouble
each have an instance forUniformRange
but noUniform
instance.- A hypothetical type
Radian
representing angles by taking values in the range[0, 2π)
has a trivialUniform
instance, but noUniformRange
instance: the problem is that two givenRadian
values always span two ranges, one clockwise and one anti-clockwise. - It is trivial to construct a
Uniform (a, b)
instance givenUniform a
andUniform b
(and this library provides this tuple instance). - On the other hand, there is no correct way to construct a
UniformRange (a, b)
instance based on justUniformRange a
andUniformRange b
.
class Uniform a where Source #
The class of types for which a uniformly distributed value can be drawn from all possible values of the type.
Since: 1.2.0
Nothing
uniformM :: StatefulGen g m => g -> m a Source #
Generates a value uniformly distributed over all possible values of that type.
There is a default implementation via Generic
:
>>>
:seti -XDeriveGeneric -XDeriveAnyClass
>>>
import GHC.Generics (Generic)
>>>
import System.Random.Stateful
>>>
data MyBool = MyTrue | MyFalse deriving (Show, Generic, Finite, Uniform)
>>>
data Action = Code MyBool | Eat (Maybe Bool) | Sleep deriving (Show, Generic, Finite, Uniform)
>>>
gen <- newIOGenM (mkStdGen 42)
>>>
uniformListM 10 gen :: IO [Action]
[Code MyTrue,Code MyTrue,Eat Nothing,Code MyFalse,Eat (Just False),Eat (Just True),Eat Nothing,Eat (Just False),Sleep,Code MyFalse]
Since: 1.2.0
Instances
uniformViaFiniteM :: (StatefulGen g m, Generic a, GFinite (Rep a)) => g -> m a Source #
A definition of Uniform
for Finite
types.
If your data has several fields of sub-Word
cardinality,
this instance may be more efficient than one, derived via Generic
and GUniform
.
>>>
:seti -XDeriveGeneric -XDeriveAnyClass
>>>
import GHC.Generics (Generic)
>>>
import System.Random.Stateful
>>>
data Triple = Triple Word8 Word8 Word8 deriving (Show, Generic, Finite)
>>>
instance Uniform Triple where uniformM = uniformViaFiniteM
>>>
gen <- newIOGenM (mkStdGen 42)
>>>
uniformListM 5 gen :: IO [Triple]
[Triple 60 226 48,Triple 234 194 151,Triple 112 96 95,Triple 51 251 15,Triple 6 0 208]
class UniformRange a where Source #
The class of types for which a uniformly distributed value can be drawn from a range.
Since: 1.2.0
Nothing
uniformRM :: StatefulGen g m => (a, a) -> g -> m a Source #
Generates a value uniformly distributed over the provided range, which is interpreted as inclusive in the lower and upper bound.
uniformRM (1 :: Int, 4 :: Int)
generates values uniformly from the set \(\{1,2,3,4\}\)uniformRM (1 :: Float, 4 :: Float)
generates values uniformly from the set \(\{x\;|\;1 \le x \le 4\}\)
The following law should hold to make the function always defined:
uniformRM (a, b) = uniformRM (b, a)
The range is understood as defined by means of isInRange
, so
isInRange (a, b) <$> uniformRM (a, b) gen == pure True
but beware of floating point number caveats.
There is a default implementation via Generic
:
>>>
:seti -XDeriveGeneric -XDeriveAnyClass
>>>
import GHC.Generics (Generic)
>>>
import Data.Word (Word8)
>>>
import Control.Monad (replicateM)
>>>
import System.Random.Stateful
>>>
gen <- newIOGenM (mkStdGen 42)
>>>
data Tuple = Tuple Bool Word8 deriving (Show, Generic, UniformRange)
>>>
replicateM 10 (uniformRM (Tuple False 100, Tuple True 150) gen)
[Tuple False 102,Tuple True 118,Tuple False 115,Tuple True 113,Tuple True 126,Tuple False 127,Tuple True 130,Tuple False 113,Tuple False 150,Tuple False 125]
Since: 1.2.0
default uniformRM :: (StatefulGen g m, Generic a, GUniformRange (Rep a)) => (a, a) -> g -> m a Source #
isInRange :: (a, a) -> a -> Bool Source #
A notion of (inclusive) ranges prescribed to a
.
Ranges are symmetric:
isInRange (lo, hi) x == isInRange (hi, lo) x
Ranges include their endpoints:
isInRange (lo, hi) lo == True
When endpoints coincide, there is nothing else:
isInRange (x, x) y == x == y
Endpoints are endpoints:
isInRange (lo, hi) x ==> isInRange (lo, x) hi == x == hi
Ranges are transitive relations:
isInRange (lo, hi) lo' && isInRange (lo, hi) hi' && isInRange (lo', hi') x ==> isInRange (lo, hi) x
There is a default implementation of isInRange
via Generic
. Other helper function
that can be used for implementing this function are isInRangeOrd
and
isInRangeEnum
Since: 1.3.0
Instances
isInRangeOrd :: Ord a => (a, a) -> a -> Bool Source #
isInRangeEnum :: Enum a => (a, a) -> a -> Bool Source #
Lists
uniformListM :: (StatefulGen g m, Uniform a) => Int -> g -> m [a] Source #
Generates a list of pseudo-random values.
Examples
>>>
import System.Random.Stateful
>>>
let pureGen = mkStdGen 137
>>>
g <- newIOGenM pureGen
>>>
uniformListM 10 g :: IO [Bool]
[True,True,True,True,False,True,True,False,False,False]
Since: 1.2.0
uniformListRM :: (StatefulGen g m, UniformRange a) => Int -> (a, a) -> g -> m [a] Source #
Generates a list of pseudo-random values in a specified range.
Examples
>>>
import System.Random.Stateful
>>>
let pureGen = mkStdGen 137
>>>
g <- newIOGenM pureGen
>>>
uniformListRM 10 (20, 30) g :: IO [Int]
[23,21,28,25,28,28,26,25,29,27]
Since: 1.3.0
uniformShuffleListM :: StatefulGen g m => [a] -> g -> m [a] Source #
Shuffle elements of a list in a uniformly random order.
Examples
>>>
import System.Random.Stateful
>>>
runStateGen_ (mkStdGen 127) $ uniformShuffleListM "ELVIS"
"LIVES"
Since: 1.3.0
Generators for sequences of pseudo-random bytes
:: StatefulGen g m | |
=> Bool | Should |
-> Int | Size of the newly created |
-> g | Generator to use for filling in the newly created |
-> m ByteArray |
uniformByteArrayM n g
generates a ByteArray
of length n
filled with pseudo-random bytes.
Since: 1.3.0
uniformByteStringM :: StatefulGen g m => Int -> g -> m ByteString Source #
Generates a pseudo-random ByteString
of the specified size.
Since: 1.2.0
uniformShortByteStringM :: StatefulGen g m => Int -> g -> m ShortByteString Source #
uniformShortByteString n g
generates a ShortByteString
of length n
filled with pseudo-random bytes.
Since: 1.3.0
Helper functions for createing instances
Sequences of bytes
:: Int | Number of bytes to generate |
-> IO Word64 | IO action that can generate 8 random bytes at a time |
-> IO ShortByteString |
Deprecated: In favor of fillByteArrayST
Efficiently fills in a new ShortByteString
in a platform independent manner.
Since: 1.2.0
genShortByteStringST :: Int -> ST s Word64 -> ST s ShortByteString Source #
Deprecated: In favor of fillByteArrayST
, since uniformShortByteString
, which it was used for, was also deprecated
Same as genShortByteStringIO
, but runs in ST
.
Since: 1.2.0
defaultUnsafeUniformFillMutableByteArray Source #
:: RandomGen g | |
=> MutableByteArray s | |
-> Int | Starting offset |
-> Int | Number of random bytes to write into the array |
-> g | ST action that can generate 8 random bytes at a time |
-> ST s g |
Efficiently generates a sequence of pseudo-random bytes in a platform independent manner.
Since: 1.2.0
Floating point numbers
uniformDouble01M :: forall g m. StatefulGen g m => g -> m Double Source #
Generates uniformly distributed Double
in the range \([0, 1]\).
Numbers are generated by generating uniform Word64
and dividing
it by \(2^{64}\). It's used to implement UniformRange
instance for
Double
.
Since: 1.2.0
uniformDoublePositive01M :: forall g m. StatefulGen g m => g -> m Double Source #
Generates uniformly distributed Double
in the range
\((0, 1]\). Number is generated as \(2^{-64}/2+\operatorname{uniformDouble01M}\).
Constant is 1/2 of smallest nonzero value which could be generated
by uniformDouble01M
.
Since: 1.2.0
uniformFloat01M :: forall g m. StatefulGen g m => g -> m Float Source #
Generates uniformly distributed Float
in the range \([0, 1]\).
Numbers are generated by generating uniform Word32
and dividing
it by \(2^{32}\). It's used to implement UniformRange
instance for Float
.
Since: 1.2.0
uniformFloatPositive01M :: forall g m. StatefulGen g m => g -> m Float Source #
Generates uniformly distributed Float
in the range
\((0, 1]\). Number is generated as \(2^{-32}/2+\operatorname{uniformFloat01M}\).
Constant is 1/2 of smallest nonzero value which could be generated
by uniformFloat01M
.
Since: 1.2.0
Enum types
uniformEnumM :: forall a g m. (Enum a, Bounded a, StatefulGen g m) => g -> m a Source #
uniformEnumRM :: forall a g m. (Enum a, StatefulGen g m) => (a, a) -> g -> m a Source #
Generates uniformly distributed Enum
in the given range.
One can use it to define a UniformRange
instance:
data Colors = Red | Green | Blue deriving (Enum) instance UniformRange Colors where uniformRM = uniformEnumRM inInRange (lo, hi) x = isInRange (fromEnum lo, fromEnum hi) (fromEnum x)
Since: 1.3.0
Word
:: StatefulGen g m | |
=> Word | Maximum value to generate |
-> g | Stateful generator |
-> m Word |
Architecture specific Word
generation in the specified lower range
Since: 1.3.0
Appendix
How to implement StatefulGen
Typically, a monadic pseudo-random number generator has facilities to save and restore its internal state in addition to generating pseudo-random numbers.
Here is an example instance for the monadic pseudo-random number generator
from the mwc-random
package:
import qualified System.Random.MWC as MWC import qualified Data.Vector.Generic as G
instance (s ~ PrimState m, PrimMonad m) => StatefulGen (MWC.Gen s) m where uniformWord8 = MWC.uniform uniformWord16 = MWC.uniform uniformWord32 = MWC.uniform uniformWord64 = MWC.uniform uniformByteArrayM isPinned n g = stToPrim (fillByteArrayST isPinned n (MWC.uniform g))
instance PrimMonad m => FrozenGen MWC.Seed m where type MutableGen MWC.Seed m = MWC.Gen (PrimState m) freezeGen = MWC.save overwriteGen (Gen mv) (Seed v) = G.copy mv v
instance PrimMonad m => ThawedGen MWC.Seed m where thawGen = MWC.restore
FrozenGen
FrozenGen
gives us ability to use most of stateful pseudo-random number generator in
its immutable form, if one exists that is. The biggest benefit that can be drawn from
a polymorphic access to a stateful pseudo-random number generator in a frozen form is
the ability to serialize, deserialize and possibly even use the stateful generator in a
pure setting without knowing the actual type of a generator ahead of time. For example
we can write a function that accepts a frozen state of some pseudo-random number
generator and produces a short list with random even integers.
>>>
import Data.Int (Int8)
>>>
import Control.Monad (replicateM)
>>>
:{
myCustomRandomList :: ThawedGen f m => f -> m [Int8] myCustomRandomList f = withMutableGen_ f $ \gen -> do len <- uniformRM (5, 10) gen replicateM len $ do x <- uniformM gen pure $ if even x then x else x + 1 :}
and later we can apply it to a frozen version of a stateful generator, such as STGen
:
>>>
print $ runST $ myCustomRandomList (STGen (mkStdGen 217))
[-50,-2,4,-8,-58,-40,24,-32,-110,24]
Alternatively, instead of discarding the final state of the generator, as it happens
above, we could have used withMutableGen
, which together with the result would give
us back its frozen form. This would allow us to store the end state of our generator
somewhere for the later reuse.
Floating point number caveats
:: forall a w. (RealFloat a, Integral w, Bounded w, FiniteBits w) | |
=> a | Low |
-> a | High |
-> w | Uniformly distributed unsigned integral value that will be used for converting to a floating point value and subsequent scaling to the specified range |
-> a |
This is the function that is used to scale a floating point value from random word range to
the custom [low, high]
range.
Since: 1.3.0
Due to rounding errors, floating point operations are neither associative nor
distributive the way the corresponding operations on real numbers are. Additionally,
floating point numbers admit special values NaN
as well as negative and positive
infinity.
The UniformRange
instances for Float
and Double
use the following
procedure to generate a random value in a range for uniformRM (l, h) g
:
- If
l == h
, return:l
. - If
orisInfinite
l == True
, return:isInfinite
h == Truel + h
Otherwise:
- Generate an unsigned integral of matching width
w
uniformly. Check whether
h - l
overflows to infinity and, if it does, then convertw
to a floating point number in[0.0, 1.0]
range through division ofw
by the highest possible value:x =
fromIntegral
w /fromIntegral
maxBound
Then we scale and clamp it before returning it:
max
(min
(x * l + (1 - x) * h) (max
l h)) (min
l h)Clamping is necessary, because otherwise it would be possible to run into a degenerate case when a scaled value is outside the specified range due to rounding errors.
Whenever
h - l
does not overflow, we use this common formula for scaling:l + (h - l) * x
. However, instead of using[0.0, 1.0]
range we use the top most bit ofw
to decide whether we will treat the generated floating point value as[0.0, 0.5]
range or[0.5, 1.0]
range and use the left over bits to produce a floating point value in the half unit range:x =
fromIntegral
(clearBit
w 31) /fromIntegral
maxBound
Further scaling depends on the top most bit:
if
testBit
w 31 then l + (h - l) * x else h + (l - h) * xBecause of this clever technique the result does not need clamping, since scaled values are guaranteed to stay within the specified range. Another reason why this tecnique is used for the common case instead of the one described in
2.
is because it avoids usage of1 - x
, which consequently reduces loss of randomness due to rounding.
- Generate an unsigned integral of matching width
What happens when NaN
or Infinity
are given to uniformRM
? We first
define them as constants:
>>>
nan = read "NaN" :: Float
>>>
inf = read "Infinity" :: Float
>>>
g <- newIOGenM (mkStdGen 2024)
If at least one of \(l\) or \(h\) is
NaN
, the result isNaN
.>>>
uniformRM (nan, 1) g
NaN>>>
uniformRM (-1, nan) g
NaNIf \(l\) and \(h\) are both
Infinity
with opposing signs, then the result isNaN
.>>>
uniformRM (-inf, inf) g
NaN>>>
uniformRM (inf, -inf) g
NaNOtherwise, if \(l\) is
Infinity
or-Infinity
, the result is \(l\).>>>
uniformRM (inf, 1) g
Infinity>>>
uniformRM (-inf, 1) g
-InfinityOtherwise, if \(h\) is
Infinity
or-Infinity
, the result is \(h\).>>>
uniformRM (1, inf) g
Infinity>>>
uniformRM (1, -inf) g
-Infinity
Note that the GCC 10.1.0 C++ standard library, the Java 10 standard library and CPython 3.8 use a similar procedure to generate floating point values in a range.
References
- Guy L. Steele, Jr., Doug Lea, and Christine H. Flood. 2014. Fast splittable pseudorandom number generators. In Proceedings of the 2014 ACM International Conference on Object Oriented Programming Systems Languages & Applications (OOPSLA '14). ACM, New York, NY, USA, 453-472. DOI: https://doi.org/10.1145/2660193.2660195