Why does [1.0, 3 ..4] contain 5?
Hi all,
Does anybody happen to know why [1.0, 3 ..4 ] is [1.0, 3.0, 5.0] ?
I do realize I'm not supposed to use enumerated lists with doubles, so this
is just a question out of pure curiosity. I ran into this example
accidentally, and I find it counter-intuitive - I would naively expect that
[x, y .. z] does not contain elements greater than z (assuming x < y < z).
The root cause of why [1.0, 3 .. 4] contains 5.0 is that in the Enum
instances for Double and Float, enumFromThenTo is defined like this:
numericEnumFromThenTo
<http://hackage.haskell.org/package/base-4.9.0.0/docs/src/GHC.Real.html#numericEnumFromThenTo>
e1 <http://hackage.haskell.org/package/base-4.9.0.0/docs/src/GHC.Real.html#local-1627413496>
e2 <http://hackage.haskell.org/package/base-4.9.0.0/docs/src/GHC.Real.html#local-1627413497>
e3 <http://hackage.haskell.org/package/base-4.9.0.0/docs/src/GHC.Real.html#local-1627413498>
= takeWhile <http://hackage.haskell.org/package/base-4.9.0.0/docs/src/GHC.List.html#takeWhile>
predicate <http://hackage.haskell.org/package/base-4.9.0.0/docs/src/GHC.Real.html#local-1627413500>
(numericEnumFromThen
<http://hackage.haskell.org/package/base-4.9.0.0/docs/src/GHC.Real.html#numericEnumFromThen>
e1 <http://hackage.haskell.org/package/base-4.9.0.0/docs/src/GHC.Real.html#local-1627413496>
e2 <http://hackage.haskell.org/package/base-4.9.0.0/docs/src/GHC.Real.html#local-1627413497>)
where
mid <http://hackage.haskell.org/package/base-4.9.0.0/docs/src/GHC.Real.html#local-1627413499>
= (e2 <http://hackage.haskell.org/package/base-4.9.0.0/docs/src/GHC.Real.html#local-1627413497>
- e1 <http://hackage.haskell.org/package/base-4.9.0.0/docs/src/GHC.Real.html#local-1627413496>)
/ <http://hackage.haskell.org/package/base-4.9.0.0/docs/src/GHC.Real.html#%2F>
2 predicate
<http://hackage.haskell.org/package/base-4.9.0.0/docs/src/GHC.Real.html#local-1627413500>
| e2 <http://hackage.haskell.org/package/base-4.9.0.0/docs/src/GHC.Real.html#local-1627413497>
>= e1 <http://hackage.haskell.org/package/base-4.9.0.0/docs/src/GHC.Real.html#local-1627413496>
= (<= e3 <http://hackage.haskell.org/package/base-4.9.0.0/docs/src/GHC.Real.html#local-1627413498>
+ <http://hackage.haskell.org/package/base-4.9.0.0/docs/src/GHC.Num.html#%2B>
mid <http://hackage.haskell.org/package/base-4.9.0.0/docs/src/GHC.Real.html#local-1627413499>)
| otherwise
<http://hackage.haskell.org/package/base-4.9.0.0/docs/src/GHC.Base.html#otherwise>
= (>= e3 <http://hackage.haskell.org/package/base-4.9.0.0/docs/src/GHC.Real.html#local-1627413498>
+ <http://hackage.haskell.org/package/base-4.9.0.0/docs/src/GHC.Num.html#%2B>
mid <http://hackage.haskell.org/package/base-4.9.0.0/docs/src/GHC.Real.html#local-1627413499>)
and with the concrete values in the example, the predicate becomes (<=5.0).
My question is this: why can't we simply use (<= e3) as the predicate? Why
is the upper limit (e3) increased by half of the length of the e1 .. e2
interval (mid)? Can someone give an example where using (<=e3) as predicate
would give a bad result?
I'm guessing that the answer has something to do with the quirks of
floating-point arithmetic (rounding etc.), of which I'm not an expert at
all :)
Regards,
Bence
Hi, I don't claim to know the real reason. But I can see that it would make some things more stable or rather it makes the stable versions look nicer. [1,1.1 .. 2] looks better than [1,1.1 .. 2.05] If you define it like you suggest numericEnumFromThenTo e1 e2 e3 = takeWhile (<=e1) [e2, e3 ..] :: [Float] I get length $ numericEnumFromThenTo 1 1.1 2 === 10 length $ numericEnumFromThenTo 2 1.2 3 === 11 Cheers, Silvio
Sorry I must be a bit tired :) On 10/19/2016 09:16 PM, Silvio Frischknecht wrote:
Hi,
I don't claim to know the real reason. But I can see that it would make some things more stable or rather it makes the stable versions look nicer.
[1,1.1 .. 2] looks better than [1,1.1 .. 2.05]
If you define it like you suggest
numericEnumFromThenTo e1 e2 e3 = takeWhile (<=e1) [e2, e3 ..] :: [Float] numericEnumFromThenTo e1 e2 e3 = takeWhile (<=e3) [e1, e2 ..] :: [Float]
I get
length $ numericEnumFromThenTo 1 1.1 2 === 10 length $ numericEnumFromThenTo 2 1.2 3 === 11 length $ numericEnumFromThenTo 2 2.1 3 == 11
Cheers, Silvio
On Wed, Oct 19, 2016 at 8:13 AM, Bence Kodaj <bence.kodaj@gmail.com> wrote:
Does anybody happen to know why [1.0, 3 ..4 ] is [1.0, 3.0, 5.0] ?
Nobody seems to know, aside from "that's what the Libraries part of the Report says". You'd probably have to find the committee that added it to the Report (good luck...) to learn their logic. (The quirks of FP arithmetic don't seem to be involved, since the overshoot is overkill for that.) -- brandon s allbery kf8nh sine nomine associates allbery.b@gmail.com ballbery@sinenomine.net unix, openafs, kerberos, infrastructure, xmonad http://sinenomine.net
My understanding is that it was intended to support enumerations where you write the exact end point, like [1.0, 1.1 .. 2.3] Because of floating point quirks, this could end up generating a value close to 2.3 that's slightly larger than the value close to 2.3 constructed by directly converting the decimal expression into a floating point number. You need to allow some "slack" in the upper bound to guarantee a value close to the written end point appears in the list. Increasing the bound by half a delta means there will be something close to 2.3 in the list, and shouldn't go far enough to include the next greater element generated. I suppose by that reasoning you're "not supposed" to use enumerations like [1.0, 3 .. 4], because 4 isn't the idealised mathematical endpoint of the sequence. On October 20, 2016 6:24:29 AM GMT+11:00, Brandon Allbery <allbery.b@gmail.com> wrote:
On Wed, Oct 19, 2016 at 8:13 AM, Bence Kodaj <bence.kodaj@gmail.com> wrote:
Does anybody happen to know why [1.0, 3 ..4 ] is [1.0, 3.0, 5.0] ?
Nobody seems to know, aside from "that's what the Libraries part of the Report says". You'd probably have to find the committee that added it to the Report (good luck...) to learn their logic. (The quirks of FP arithmetic don't seem to be involved, since the overshoot is overkill for that.)
-- brandon s allbery kf8nh sine nomine associates allbery.b@gmail.com ballbery@sinenomine.net unix, openafs, kerberos, infrastructure, xmonad http://sinenomine.net
------------------------------------------------------------------------
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.
participants (4)
-
Ben Mellor -
Bence Kodaj -
Brandon Allbery -
Silvio Frischknecht