Re: [Haskell-cafe] instance Enum Double considered not entirelygreat?

2011-09-26 Thread Donn Cave
Quoth Richard O'Keefe o...@cs.otago.ac.nz,

 [ ... re  Why would you write
   an upper bound of 0.3 on a list if you don't expect that to be included
   in the result?  ]

 Because upper bounds are *UPPER BOUNDS* and are NOT as a rule included
 in the result.  If you write [0,2..9] you
  - DO expect 0 in the result
  - DON'T expect 9 in the result
  - would be outraged if 10 were in the result.

Pardon the questions from the gallery, but ... I can sure see that
0.3 shouldn't be included in the result by overshooting the limit
(i.e., 0.30004), and the above expectations about
[0,2..9] are obvious enough, but now I have to ask about [0,2..8] -
would you not expect 8 in the result?  Or is it not an upper bound?

Donn

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] instance Enum Double considered not entirelygreat?

2011-09-26 Thread Chris Smith
On Mon, 2011-09-26 at 19:54 -0700, Donn Cave wrote:
 Pardon the questions from the gallery, but ... I can sure see that
 0.3 shouldn't be included in the result by overshooting the limit
 (i.e., 0.30004), and the above expectations about
 [0,2..9] are obvious enough, but now I have to ask about [0,2..8] -
 would you not expect 8 in the result?  Or is it not an upper bound?

Donn,

[0, 2 .. 8] should be fine no matter the type, because integers of those
sizes are all exactly representable in all of the types involved.  The
reason for the example with a step size of 0.1 is that 0.1 is actually
an infinitely repeating number in base 2 (because the denominator has a
prime factor of 5).  So actually *none* of the exact real numbers 0.1,
0.2, or 0.3 are representable with floating point types.  The
corresponding literals actually refer to real numbers that are slightly
off from those.

Furthermore, because the step size is not *exactly* 0.1, when it's added
repeatedly in the sequence, the result has some (very small) drift due
to repeated rounding error... just enough that by the time you get in
the vacinity of 0.3, the corresponding value in the sequence is actually
*neither* the rational number 0.3, *nor* the floating point literal 0.3.
Instead, it's one ulp larger than the floating point literal because of
that drift.

So there are two perspectives here.  One is that we should think in
terms of exact values of the type Float, which means we'd want to
exclude it, because it's larger than the top end of the range.  The
other is that we should think of approximate values of real numbers, in
which case it's best to pick the endpoint closest to the stated one, to
correct for what's obviously unintended drift due to rounding.

So that's what this is about: do we think of Float as an approximate
real number type, or as an exact type with specific values.  If the
latter, then of course you exclude the value that's larger than the
upper range.  If the former, then using comparison operators like ''
implies a proof obligation that the result of the computation remains
stable (loosely speaking, the function continuous) at that boundary
despite small rounding error in either direction.  In that case,
creating a language feature where, in the *normal* case of listing the
last value you expect in the list, 0.3 (as an approximate real number)
is excluded from this list just because of technicalities about the
representation is an un-useful implementation, to say the least, and
makes it far more difficult to satisfy that proof obligation.

Personally, I see floating point values as approximate real numbers.
Anything else in unrealistic: the *fact* of the matter is that no one is
reasoning about ulps or exact rational values when they use Float and
Double.  In practice, even hardware implementations of some floating
point functions have indeterminate results in the exact sense.  Often,
the guarantee provided by an FPU is that the result will be within one
ulp of the correct answer, which means the exact value of the answer
isn't even known!  So, should we put all floating point calculations in
the IO monad because they aren't pure functions?  Or can we admit that
people use floating point to approximate reals and accept the looser
reasoning?

-- 
Chris Smith



___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] instance Enum Double considered not entirelygreat?

2011-09-26 Thread Richard O'Keefe

On 27/09/2011, at 3:54 PM, Donn Cave wrote:

 Quoth Richard O'Keefe o...@cs.otago.ac.nz,
 
 [ ... re  Why would you write
   an upper bound of 0.3 on a list if you don't expect that to be included
   in the result?  ]
 
 Because upper bounds are *UPPER BOUNDS* and are NOT as a rule included
 in the result.  If you write [0,2..9] you
 - DO expect 0 in the result
 - DON'T expect 9 in the result
 - would be outraged if 10 were in the result.
 
 Pardon the questions from the gallery, but ... I can sure see that
 0.3 shouldn't be included in the result by overshooting the limit
 (i.e., 0.30004), and the above expectations about
 [0,2..9] are obvious enough, but now I have to ask about [0,2..8] -
 would you not expect 8 in the result?  Or is it not an upper bound?

Quoting the Wikipedia:
In mathematics, especially in order theory,
an upper bound of a subset S of some partially ordered set (P, ≤)
is an element of P which is greater than or equal to
every element of S.  ^^^

In the case of integers, where is the overshoot?

I expect [L,M..U] to be the collection of all x
such that L = x = U and x-L is n*(M-L) for some
n, if M = L, or the collection of all x such that
U = x = L and x-L is n*(M-L) for some n, if M = L.

I don't say that's what Haskell promises.  What I say
is that that's what I _expect_.  On the rare occasions
when I've used REAL DO, getting close to the stated
end point has been unimportant; not going outside the
stated bounds critically important.

In the case of [0,2..8], 0 = 8 = 8 and 8-0 is 4*(2-0),
so 8 should be there.

[0,1/10..3/10] :: [Ratio Int]  includes 3/10 as it should;
3/10 = 3/10 so that's fine too.


___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] instance Enum Double considered not entirelygreat?

2011-09-26 Thread Richard O'Keefe

On 27/09/2011, at 4:55 PM, Chris Smith wrote:
 So there are two perspectives here.  One is that we should think in
 terms of exact values of the type Float, which means we'd want to
 exclude it, because it's larger than the top end of the range.  The
 other is that we should think of approximate values of real numbers, in
 which case it's best to pick the endpoint closest to the stated one, to
 correct for what's obviously unintended drift due to rounding.

My perspective on this is neither of the above.
My perspective is that if I say I want numbers in the range L..U,
anything outside that range is wrong and could be catastrophically
wrong.

 So that's what this is about: do we think of Float as an approximate
 real number type, or as an exact type with specific values.

That may be the way you see it, but it's not the way I see it.
The way I see it is that the *order* properties are more fundamental
than the *arithmetic* properties, and that it is far less important
to produce value which is approximately the end point (after all,
[0,2..9] doesn't include 10) than it is to ensure that all the
results are in the interval.

And I would be *delighted* if Haskell's compare raised an exception
if either argument were a NaN; that's what Real.compare does in SML.

Floating point *operations* are approximate;
floating point *numbers* are, according to the relevant standards
(IEEE, LIA), precise.



___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] instance Enum Double considered not entirelygreat?

2011-09-20 Thread Donn Cave
Quoth Chris Smith cdsm...@gmail.com,
...
 As for Enum, if someone were to want a type class to represent an
 enumeration of all the values of a type, then such a thing is reasonable
 to want.  Maybe you can even reasonably wish it were called Enum.  But
 it would be the *wrong* thing to use as a desugaring for list range
 notation.  List ranges are very unlikely to be useful or even meaningful
 for most such enumerations (what is [ Red, Green .. LightPurple]?); and
 conversely, as we've seen in this thread, list ranges *are* useful in
 situations where they are not a suitable way of enumerating all values
 of a type.

It isn't a life or death requirement, but I have dealt with enum values
that are ordered and that could usefully be represented in a range.
Even your example -- given a set of hues, it's sensible to order them
following the spectrum, so [Cyan .. YellowGreen] might represent the
hues in the set that are at all in the green range.

I'm frankly using Enum as an equivalent to C enum, symbolic integers,
where the range is more or less implicit as by default the integer values
are [0..].  While I (vaguely) understand that Haskell's Enum is different,
the C idiom should at least testify that there's some practical value
in the notion of a range of Enum, or something like it.  Though not
with floating point values, of course.

Donn

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe