Skip to content

QuickCheck: coarbitrary for Double and Float is broken.

The coarbitrary definition for these types is incompatible with the way they are generated. First, decodeFloat produces a pair (Integer, Int), then the Integer is manipulated to be positive and then coerced to an Int using fromInteger and passed to variant. Even 'simple' values of type Double and Float (as produced by arbitrary) can have huge significands. In the case of Double, the resulting Int can be negative due to truncation. This causes an exception when variant uses '(!!)' with a negative index. Huge positive values are just as bad since they cause a space leak while evaluating variant with a huge index (and tend not to terminate due to memory constraints). An obvious fix is to use the QuickCheck-2 approach.

To reproduce, import Test.QuickCheck and Text.Show.Functions, then run:

verboseCheck ((\f a -> f a == f a) :: (Float -> Int) -> Float -> Bool)

This should pass a few tests before finding a space leak.

verboseCheck ((\f a -> f a == f a) :: (Double -> Int) -> Double -> Bool)

This should also pass a few, then it may find a space leak, or it may error with:

*** Exception: Prelude.(!!): negative index

Note that QuickCheck-2 has no problems here.

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