I found myself having a case where the equivalent of floor $ 1/0
was being executed.
λ> 1/0
Infinity
This is normal behavior as far as I understand but, when Infinity
is floor
'd or ceiling
'd
λ> floor $ 1/0
179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639474124377767893424865485276302219601246094119453082952085005768838150682342462881473913110540827237163350510684586298239947245938479716304835356329624224137216
Instead of failing, this very big number is produced. Why?
Maybe more importantly, how can I distinguish this from a non faulty result without using a filter before applying another function?
The first question is perhaps not so important, so I'll try to answer the second question first.
Once you have a number, if you know that it came from floor x
, you can't know whether x
was the valid representation of 2^1024
or if it was infinity. You can probably assume anything outside of the range of double is invalid and was produced from infinity, negative infinity, NaN or the like. It would be quite simple to check if your value is valid using one/many of the functions in RealFloat
, like isNaN
, isInfinite
, etc.
You could also use something like data Number a = N a | PosInf | NegInf
. Then you write:
instance RealFrac a => RealFrac (Number a) where
...
floor (N n) = floor n
floor PosInf = error "Floor of positive infinity"
floor NegInf = error "Floor of negative infinity"
..
Which approach is best is based mostly on your use case.
Maybe it would be correct for floor (1/0)
to be an error. But the value is garbage anyways. Is it better to deal with garbage or an error?
But why 2^1024
? I took a look at the source for GHC.Float
:
properFraction (F# x#)
= case decodeFloat_Int# x# of
(# m#, n# #) ->
let m = I# m#
n = I# n#
in
if n >= 0
then (fromIntegral m * (2 ^ n), 0.0)
else let i = if m >= 0 then m `shiftR` negate n
else negate (negate m `shiftR` negate n)
f = m - (i `shiftL` negate n)
in (fromIntegral i, encodeFloat (fromIntegral f) n)
floor x = case properFraction x of
(n,r) -> if r < 0.0 then n - 1 else n
Note that decodeFloat_Int#
returns the mantissa and exponent. According to wikipedia:
Positive and negative infinity are represented thus: sign = 0 for positive infinity, 1 for negative infinity. biased exponent = all 1 bits. fraction = all 0 bits.
For Float
, this means a base of 2^23, since there are 23 bits in the base, and an exponent of 105 (why 105? I actually have no idea. I would think it should be 255 - 127 = 128, but it seems to actually be 128 - 23). The value of floor
is fromIntegral m * (2 ^ n)
or base*(2^exponent) == 2^23 * 2^105 == 2^128
. For double this value is 1024.