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?
In languages like C, C++ etc. division by zero invokes undefined behaviour. So according to the language definition, anything can happen.
Dividing a number by Zero is a mathematical error (not defined) and we can use exception handling to gracefully overcome such operations. If you write a code without using exception handling then the output of division by zero will be shown as infinity which cannot be further processed.
Dividing by zero is an operation that has no meaning in ordinary arithmetic and is, therefore, undefined.
'0' is the char value of zero. When you write a string, you're writing an array of 'char' datatypes which the compiler translates into ASCII values (which have a corresponding decimal number value).
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With