Skip to content

Random instance for Double can generate values out of requested range

There appears to be an off-by-one error in randomIvalDouble, causing it to return values outside the requested range one time out of every few billion (exact frequency depending on the bounds of Int):

Prelude Control.Monad System.Random> (filter (<= 0) . randomRs (0,1)) `fmap` newStdGen :: IO [Double]
Loading package random-1.0.0.2 ... linking ... done.
[-1.1641532182693481e-10,-1.1641532182693481e-10^CInterrupted.

The problem appears to arise because int32Range does not represent the number of possible Int32's returned by the call to randomIvalInteger. Changing the division by int32Range in the definition of scaled_x to division by (int32Range + 1) should fix it. Attached is a darcs patch implementing this change. I don't actually know whether the resulting code reflects the intent of the interface, however. This version will produce the lower bound but not the upper bound.

Additionally, with or without the attached patch the basic structure of the scaling (adding a scaled Int32 to the midpoint of the range) does not play well with floating-point math in the first place: for example, randomR (exp 1, pi :: Double) can return a value one ULP less than 'exp 1'. This could probably be avoided by sampling a Word32 instead of an Int32 and adding the corresponding fraction of the range size to the lower bound.

Trac metadata
Trac field Value
Version 6.12.1
Type Bug
TypeOfFailure OtherFailure
Priority normal
Resolution Unresolved
Component libraries/random
Test case
Differential revisions
BlockedBy
Related
Blocking
CC
Operating system
Architecture
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information