It’s not floor
that is losing precision, but the conversion from Integer
(an arbitrary-precision integer) to Double
(a floating-point value, which has a limited precision). Accordingly, fromIntegral n :: Double
is no longer the same value as n
.
Double
has a 53-bit mantissa (52 explicitly stored, the leading one implicit), which is approximately equivalent to 16 decimal digits. Thus, only the (approx.) 16 most significant digits of the result are valid. The rest is just noise.
Finally, your first two comparisons compare Double
s; and n
converted into Double
, s2
converted into Double
, and s1
are all equal. In the third comparison, however, n
and s2
are both Integer
s; they can be compared as Integer
s, so calling fromIntegral
on them is a no-op, and their non-converted integer values are different. If you force conversion to Double
, the values become equal again:
Prelude> ((fromIntegral n) :: Double) == ((fromIntegral s2) :: Double)
True