
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