0

Possible Duplicate:
Haskell ranges and floats

For example, when I type

[0.1, 0.3 ..1]

I get this:

[0.1,0.3,0.5,0.7,0.8999999999999999,1.0999999999999999]

I expected:

[0.1,0.3,0.5,0.7,0.9]
Community
  • 1
  • 1
David Degea
  • 1,378
  • 2
  • 12
  • 18

3 Answers3

3

Try

map (/10) [1, 3 .. 10]

instead.


The problem is that floating point numbers use binary fractions, and binary fractions can't exactly represent decimal fractions. So you get errors and the errors build up.

A binary fraction cannot exactly represent 1/5 in the same way that a decimal fraction cannot exactly represent 1/3 --- the best we can do is 0.33333....

[0.1, 0.3 .. 1] is shorthand for

[0.1,
 0.1 + 0.2,
 0.1 + 0.2 + 0.2,
 0.1 + 0.2 + 0.2 + 0.2,
 0.1 + 0.2 + 0.2 + 0.2 + 0.2,
 0.1 + 0.2 + 0.2 + 0.2 + 0.2 + 0.2]

The other problem is that the list will stop after the first element that is equal to or past the limit when the next element would be more than half the step past the limit, which is why you have the 1.0999999999999999 element.

dave4420
  • 46,404
  • 6
  • 118
  • 152
  • I can understand 0.89999 because the float can't be represent exactly. But why the list generated has the value 1.099999 exceed value 1. – RolandXu Apr 26 '12 at 06:53
  • 3
    But [1,3 .. 10] results [1,3,5,7,9]. Has no value 11 which is the first element that past the limit. – RolandXu Apr 26 '12 at 07:00
  • 4
    @RolandXu The real rule for `Double` is that it will go until the number is more than half-way past the ending condition. Compare `[1,4..6] :: [Int]`, `[1,4..6] :: [Double]`, and `[1.6,4.6..6] :: [Double]`. – Daniel Wagner Apr 26 '12 at 07:20
  • 3
    It's a bug in the Haskell spec, introduced by some well meaning people. It's totally wrong to have the last element exceed the upper bound, IMO. – augustss Apr 26 '12 at 07:22
  • @augustss: would you agree that an Enum instance for floats is also totally wrong? – John L Apr 26 '12 at 08:48
  • No, I don't agree that Enum for float is totally wrong. But you have to understand what you're doing to use it, so perhaps it shouldn't be part of the standard instances. – augustss Apr 26 '12 at 09:25
  • 1
    `map ((/10) . fromInteger) [1, 3 .. 10]` would be more robust. – Rotsor Apr 26 '12 at 10:45
1

This is an issue with how floating point numbers are represented in the computer. Simple arithmetic with floating point numbers often does not behave as expected. Repeated arithmetic can accumulate "rounding error", which means the result can get progressively worse as you repeatedly add numbers (for example).

You can avoid these problems in some cases by using a different numerical representation. If you only care about rational numbers, for example, you could use the Rational type. So you could do:

[0.1,0.3..1] :: [Rational]

which results in:

[1 % 10,3 % 10,1 % 2,7 % 10,9 % 10,11 % 10]

This is the correct answer with no rounding error; each number is just represented as the ratio of two Integers. Depending on your particular situation, this may be a better option than using floating point numbers.

This does still go over the upper bound, but that is much easier to deal with than the rounding error you get from floating point numbers.

Note that for something performance critical floating point numbers are probably going to be faster.

Tikhon Jelvis
  • 67,485
  • 18
  • 177
  • 214
  • The fact that the `Rational` instance uses the same rule boggles my mind. It's somewhat defensible for `Double` because it defeats some rounding problems when the ending bound is put in the right place, but for `Rational` there's no rounding! – Daniel Wagner Apr 26 '12 at 17:19
1

The expression [e1, e2 .. e3] is evaluated as enumFromThenTo e1 e2 e3, which for floating point numbers means (from The Haskell 98 Report):

For Float and Double, the semantics of the enumFrom family is given by the rules for Int above, except that the list terminates when the elements become greater than e3+i/2 for positive increment i, or when they become less than e3+i/2 for negative i.

This means that with floating point numbers the last element of [e1, e2 .. e3] is often greater than e3, and can be up to e3+(e2-e1)/2 - ε.

Joni
  • 108,737
  • 14
  • 143
  • 193