I am finding the list of [0.1..1]
that will be returned from Haskell and I do not understand why it is [0.1,1.1]
. Can anyone provide explanation for me please?
CodePudding user response:
TL;DR: don't use [x..y]
on floating point numbers. You might get unexpected results.
On floating point numbers, there's no sane semantics for [x..y]
. For instance, one might argue that the semantics should be [x,x 1,x 2,...,x n]
where x n
is the largest value of that form which is <=y
. However, this does not account for floating point rounding errors. It is possible that x n
produces a slightly larger value than the exact y
, making the list shorter than expected. Hence this semantics makes the value of length [x..y]
rather unpredictable.
Haskell tries to mitigate this issue, by allowing an error up to 0.5
. The rationale is as follows: when x n
is closer to y
than to y 1
, it should be regarded as some value in the interval [x..y]
which got rounded to something larger. Arguable, but this is how Haskell works.
In enumerations like [x,y .. z]
with an explicit stepping (e.g. [0.0,5.0 .. 1000.0]
) Haskell instead allows an error of (y-x)/2
(2.5
in the example). The rationale is the same: we include those points which are closer to 1000
than to 1000 5
.
You can find all the gory details in the Haskell Report which defines the semantics of Haskell. This part is also relevant.
This is generally seen by Haskellers as a small wart in the language. Some argue that we should not have mandated Enum Float
and Enum Double
. Removing those instances would effectively prohibit the troublesome cases like [1.0 .. 5.0]
or the much worse [1.0 .. 5.5]
(which is again numerically unstable).