[commit: packages/random] master: fix for randomIvalInteger, ghc #8898 (031a557)
git at git.haskell.org
git at git.haskell.org
Thu Mar 19 15:44:42 UTC 2015
Repository : ssh://git@git.haskell.org/random
On branch : master
Link : http://git.haskell.org/packages/random.git/commitdiff/031a5574ebf31d956f077a16f3fc38c39ca284a3
>---------------------------------------------------------------
commit 031a5574ebf31d956f077a16f3fc38c39ca284a3
Author: Ken Bateman <novadenizen at gmail.com>
Date: Sat Mar 22 20:42:44 2014 +0000
fix for randomIvalInteger, ghc #8898
>---------------------------------------------------------------
031a5574ebf31d956f077a16f3fc38c39ca284a3
System/Random.hs | 42 ++++++++++++++++++++++--------------------
1 file changed, 22 insertions(+), 20 deletions(-)
diff --git a/System/Random.hs b/System/Random.hs
index 844dea8..665dd78 100644
--- a/System/Random.hs
+++ b/System/Random.hs
@@ -444,24 +444,33 @@ randomBounded = randomR (minBound, maxBound)
randomIvalIntegral :: (RandomGen g, Integral a) => (a, a) -> g -> (a, g)
randomIvalIntegral (l,h) = randomIvalInteger (toInteger l, toInteger h)
+{-# SPECIALIZE randomIvalInteger :: (Num a) =>
+ (Integer, Integer) -> StdGen -> (a, StdGen) #-}
+
randomIvalInteger :: (RandomGen g, Num a) => (Integer, Integer) -> g -> (a, g)
randomIvalInteger (l,h) rng
| l > h = randomIvalInteger (h,l) rng
- | otherwise = case (f n 1 rng) of (v, rng') -> (fromInteger (l + v `mod` k), rng')
+ | otherwise = case (f 1 0 rng) of (v, rng') -> (fromInteger (l + v `mod` k), rng')
where
+ (genlo, genhi) = genRange rng
+ b = fromIntegral genhi - fromIntegral genlo + 1
+
+ -- Probabilities of the most likely and least likely result
+ -- will differ at most by a factor of (1 +- 1/q). Assuming the RandomGen
+ -- is uniform, of course
+
+ -- On average, log q / log b more random values will be generated
+ -- than the minimum
+ q = 1000
k = h - l + 1
- -- ERROR: b here (2^31-87) represents a baked-in assumption about genRange:
- b = 2147483561
- n = iLogBase b k
-
- -- Here we loop until we've generated enough randomness to cover the range:
- f 0 acc g = (acc, g)
- f n' acc g =
- let
- (x,g') = next g
- in
- -- We shift over the random bits generated thusfar (* b) and add in the new ones.
- f (n' - 1) (fromIntegral x + acc * b) g'
+ magtgt = k * q
+
+ -- generate random values until we exceed the target magnitude
+ f mag v g | mag >= magtgt = (v, g)
+ | otherwise = v' `seq`f (mag*b) v' g' where
+ (x,g') = next g
+ v' = (v * b + (fromIntegral x - fromIntegral genlo))
+
-- The continuous functions on the other hand take an [inclusive,exclusive) range.
randomFrac :: (RandomGen g, Fractional a) => g -> (a, g)
@@ -484,13 +493,6 @@ randomIvalDouble (l,h) fromDouble rng
int32Count :: Integer
int32Count = toInteger (maxBound::Int32) - toInteger (minBound::Int32) + 1
--- Perform an expensive logarithm on arbitrary-size integers by repeated division.
---
--- (NOTE: This actually returns ceiling(log(i) base b) except with an
--- incorrect result at iLogBase b b = 2.)
-iLogBase :: Integer -> Integer -> Integer
-iLogBase b i = if i < b then 1 else 1 + iLogBase b (i `div` b)
-
stdRange :: (Int,Int)
stdRange = (0, 2147483562)
More information about the ghc-commits
mailing list