module Data.Tempo.Random (countToRand, countToRands) where import Data.Bits xorwise :: Int -> Int xorwise x = let a = xor (shiftL x 13) x b = xor (shiftR a 17) a in xor (shiftL b 5) b countToIntSeed :: RealFrac a => a -> Int countToIntSeed = xorwise . truncate . (* 536870912) . snd . (properFraction :: (RealFrac a => a -> (Int,a))) . (/ 300) intSeedToRand :: Fractional a => Int -> a intSeedToRand = (/ 536870912) . realToFrac . (`mod` 536870912) -- | countToRand converts a count (eg. measure of elapsed 'time' in a Tempo) to -- a random value in the range [0,1) by stretching 300 counts over the range of -- [0,2**29 == 536870912) and then apply a 'xorshift' algorithm. For the latter: -- cf. George Marsaglia (2003). "Xorshift RNGs". Journal of Statistical Software 8:14. -- https://www.jstatsoft.org/article/view/v008i14 countToRand :: (RealFrac a, Fractional b) => a -> b countToRand = intSeedToRand . countToIntSeed -- | countToRands generates multiple pseudo-random values by converting the provided -- count as with countToRand and then recursively using the values calculated to -- generate additional pseudo-random values, as in the 'normal' usage of a pseudo- -- random number geneator. countToRands :: (RealFrac a, Fractional b) => a -> Int -> [b] countToRands t n = countToRands' (countToIntSeed t) n countToRands' :: Fractional a => Int -> Int -> [a] countToRands' seed n | n <= 0 = [] | otherwise = (intSeedToRand seed) : (countToRands' (xorwise seed) (n-1))