floor, ceiling, round :: Double -> Int are awesomely slow
We have super-naive implementations of the RealFrac class for Double.
Consider:
{-# RULES "truncate/Double->Int" truncate = double2Int #-}
instance RealFrac Double where
properFraction x
= case (decodeFloat x) of { (m,n) ->
let b = floatRadix x in
if n >= 0 then
(fromInteger m * fromInteger b ^ n, 0.0)
else
case (quotRem m (b^(negate n))) of { (w,r) ->
(fromInteger w, encodeFloat r n)
}
}
floor x = case properFraction x of
(n,r) -> if r < 0.0 then n - 1 else n
So now, we *do* have a good rule for truncate, but floor, ceiling and round turn out to be awesomely slow.
main = print . sumU
. mapU (floor :: Double -> Int)
$ enumFromToFracU 0 100000000
Runs in 1 minute, 10 seconds:
$ time ./henning
5000000050000000
./henning 70.25s user 0.17s system 99% cpu 1:10.99 total
Now, if we just replace that with a ccall to math.h:floor, we get:
main = print . sumU
. mapU (floor' :: Double -> Int)
$ enumFromToFracU 0 100000000
floor' :: Double -> Int
floor' x = (truncate :: Double -> Int) (c_floor x)
{-# INLINE floor' #-}
foreign import ccall unsafe "math.h floor"
c_floor :: Double -> Double
Which runs in 1.8 seconds:
$ time ./henning
5000000050000000
./henning 1.88s user 0.00s system 99% cpu 1.884 total
Similar results for ceiling and round (see the main ticket for RealFrac, http://hackage.haskell.org/trac/ghc/ticket/1434)
Action
Use math.h versions of round, floor and ceiling for Double and Float?
Trac metadata
Trac field | Value |
---|---|
Version | 6.8.2 |
Type | Bug |
TypeOfFailure | OtherFailure |
Priority | normal |
Resolution | Unresolved |
Component | Compiler |
Test case | |
Differential revisions | |
BlockedBy | |
Related | |
Blocking | |
CC | |
Operating system | Unknown |
Architecture | Unknown |