Home > other >  In Haskell, [0.1..1] returns [0.1,1.1]. Why? [duplicate]
In Haskell, [0.1..1] returns [0.1,1.1]. Why? [duplicate]

Time:10-07

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).

  • Related