2

I've just started playing with GHCi. I see that list generators basically solve an equation within a given set:

Prelude> [x | x <- [1..20], x^2 == 4]
[2]

(finds only one root, as expected)

Now, why can't I solve equations with results in ℝ, given that the solution is included in the specified range?

[x | x <- [0.1,0.2..2.0], x*4 == 2]

How can I solve such equations within real numbers set?

Edit: Sorry, I meant 0.1, of course.

Erik Kaplun
  • 37,128
  • 15
  • 99
  • 111
PJK
  • 2,082
  • 3
  • 17
  • 28
  • 1
    Ah, by 'R' you mean the real numbers, not the language R! Unfortunately, there is no way to generate the set of all the members of R in between two numbers (or all the floats), which would be an incredibly large set. – Andrew Jaffe Feb 13 '11 at 12:16
  • 3
    @Andrew... more than incredibly large :-) let's not hide him the Truth any longer: there are **infinite** Real values between 0.001 and 0.01. Infinite. More than the ridiculously litte huge-number of particles that a sealed universe could ever contain. :) – Stephane Rolland Feb 13 '11 at 13:21
  • 2
    Worth noting: list comprehensions like the simple one you have given can be written simply as `filter ((==2).(*4)) xs` – Dan Burton Feb 13 '11 at 22:02
  • 2
    @Stephane... I meant that there is an incredibly large (but finite) number of representable floating-point numbers between 0 and 2 of a particular size (e.g., 64-bit). – Andrew Jaffe Feb 13 '11 at 23:18

4 Answers4

8

List comprehension doesn't solve equations, it just generates a list of items that belong to certain sets. If your set is defined as any x in [1..20] such that x^2==4, that's what you get.

You cannot do that with a complete list of any real number from 0.01 to 2.0, because such real list cannot be represented in haskell (or better: it cannot be represented on any computer), since it has infinite numbers with infinite precision.

[0.01,0.2..2.0] is a list made of the following numbers:

Prelude> [0.01,0.2..2.0]
[1.0e-2,0.2,0.39,0.5800000000000001,0.7700000000000001,0.9600000000000002,1.1500000000000004,1.3400000000000005,1.5300000000000007,1.7200000000000009,1.910000000000001]

And none of these numbers satisfies your condution.


Note that you probably meant [0.1,0.2..2.0] instead of [0.01,0.2..2.0]. Still:

Prelude> [0.1,0.2..2.0]
[0.1,0.2,0.30000000000000004,0.4000000000000001,0.5000000000000001,0.6000000000000001,0.7000000000000001,0.8,0.9,1.0,1.1,1.2000000000000002,1.3000000000000003,1.4000000000000004,1.5000000000000004,1.6000000000000005,1.7000000000000006,1.8000000000000007,1.9000000000000008,2.000000000000001]
peoro
  • 25,562
  • 20
  • 98
  • 150
  • And even if you could generate a list of all the floating-point representations between 0 and 2, this would be an incredibly inefficient way to "solve" the equation, as it just searches one by one from the beginning to the end. – Andrew Jaffe Feb 13 '11 at 12:18
  • You could try to fix the type to `Rational` instead. – fuz Feb 13 '11 at 12:32
  • @Andrew Jaffe, further, a solution may not even exist in the floating point numbers. `(sqrt 2)^2 == 2 ---> False`. – luqui Feb 13 '11 at 22:04
5

As others have mentioned, this is not an efficient way to solve equations, but it can be done with ratios.

Prelude> :m +Data.Ratio 
Prelude Data.Ratio> [x|x<-[1%10, 2%10..2], x*4 == 2]
[1 % 2]

Read x % y as x divided by y.

Dan Burton
  • 53,238
  • 27
  • 117
  • 198
4

The floating point issue can be solved in this way:

Prelude> [x | x <- [0.1, 0.2 .. 2.0], abs(2 - x*4) < 1e-9]
[0.5000000000000001]

For a reference why floating point numbers can make problems see this: Comparing floating point numbers

Mariy
  • 5,746
  • 4
  • 40
  • 57
  • This does work for the specific example, but a fixed epsilon of 10⁻⁹ really isn't very reliable, because floating-point inaccuracy isn't absolute. (If the numbers get too small, you may get a whole cloud of false positives, if they are too big again none may satisfy.) To solve equations with floating-point numbers, one should either use a proper solver (Newton-Raphson) or at least compare the _relative_ deviations. – leftaroundabout Nov 01 '15 at 09:28
3

First of all [0.01,0.2..2.0] wouldn't include 0.5 even if floating point arithmetic were accurate. I assume you meant the first element to be 0.1.

The list [0.1,0.2..2.0] does not contain 0.5 because floating point arithmetic is imprecise and the 5th element of [0.1,0.2..2.0] is 0.5000000000000001, not 0.5.

luqui
  • 59,485
  • 12
  • 145
  • 204
sepp2k
  • 363,768
  • 54
  • 674
  • 675