# [Haskell-cafe] instance Enum Double considered notentirelygreat?

Chris Smith cdsmith at gmail.com
Tue Sep 27 17:49:42 CEST 2011

```On Tue, 2011-09-27 at 00:29 -0700, Donn Cave wrote:
> It doesn't appear to me to be a technicality about the representation -
> the value we're talking about excluding is not just represented as
> greater than 0.3, it is greater than 0.3 when applied in computations.

Sure, the exact value is greater than 0.3.  But to *predict* that, you
have to know quite a bit about the technicalities of how floating point
values are represented.  For example, you need to know that 0.1 has no
exact representation as a floating point number, and that the closest
approximation is greater than the exact real number 0.1, and that the
difference is great enough that adding it twice adds up to a full ulp of
error.

> For example you can subtract 0.3 and get a nonzero value (5.55e-17.)

Again, if you're working with floating point numbers and your program
behaves in a significantly different way depending on whether you get 0
or 5.55e-17 as a result, then you're doing something wrong.

> The disappointment with iterative addition is not that
> its fifth value [should be] omitted because it's "technically" greater,
> it's that range generation via iterative addition does not yield the
> values I specified.

I certainly don't agree that wanting the exact value from a floating
point type is a reasonable expectation.  The *only* way to recover those
results is to do the math with the decimal or rational values instead of
floating point numbers.  You'll get the rounding error from floating
point regardless of how you do the computation, because the interval
just isn't really 0.1.  The difference between those numbers is larger
than 0.1, and when you step by that interval, you won't hit 0.5.

You could calculate the entire range using Rational and then convert
each individual value after the fact.  That doesn't seem like a
reasonable default, since it has a runtime performance cost.  Of course
you're welcome to do it when that's what you need.

> last ([0.1, 0.2 .. 0.5]) == 0.5
False

> last (map fromRational [0.1, 0.2 .. 0.5]) == 0.5
True

--
Chris

```