-----Original Message----- From: Peter Crowther [SMTP:Peter.Crowther@IT-IQ.com] Sent: Tuesday, November 30, 1999 9:25 AM To: 'squeak@cs.uiuc.edu' Subject: RE: Intervals
You're still assuming steps at, or of the order of, 1.
<sigh> Guilty as charged. I also confess to having missed an edge condition. Dare I hope for a velvet rope with which to be hung, m'lud? :-)
'From Squeak2.6 of 11 October 1999 [latest update: #1559] on 30 November 1999 at 11:07:18 am'!
!Interval methodsFor: 'accessing' stamp: 'rpj 11/30/1999 11:04'! includes: aNumber "Determine if aNumber is an element of this interval." ^(self rangeIncludes: aNumber) and: [ self valuesInclude: aNumber ]! !
!Interval methodsFor: 'private' stamp: 'rpj 11/30/1999 11:01'! rangeIncludes: aNumber "Private" ^aNumber between: (self first min: self last) and: (self first max: self last)! !
!Interval methodsFor: 'private' stamp: 'rpj 11/30/1999 11:04'! valuesInclude: aNumber "Private - answer whether or not aNumber is one of the enumerated values in this interval." ^(aNumber - self first \ step = 0) or: [ ((aNumber - self first \ step - step) abs < (step * 1e-10) abs) or: [ (aNumber - self first \ step) abs < (step * 1e-10) abs ] ]! !
I know the addition of a fudge factor may cause problems in some cases, but it does (help) Squeak support Dan's Principle of Least Astonishment. To me it's quite amazing that Squeak says
(1.0 to: 20.0 by: 0.2) includes: 1.2 ==> false
while it's (a bit) less amazing for it to say
(1.0 to: 20.0 by: 0.2) includes: 19.999999999999 ==> true
Of course, all this mucking about with Floats is going to come back to haunt us at some later date. Floats, as I think I've mentioned in the past, are evil...
Bob Jarvis Compuware @ Timken
At 11:21 -0500 11/30/99, Jarvis, Robert P. wrote:
-----Original Message----- From: Peter Crowther [SMTP:Peter.Crowther@IT-IQ.com] Sent: Tuesday, November 30, 1999 9:25 AM To: 'squeak@cs.uiuc.edu' Subject: RE: Intervals
You're still assuming steps at, or of the order of, 1.
<sigh> Guilty as charged. I also confess to having missed an edge condition. Dare I hope for a velvet rope with which to be hung, m'lud? :-)
'From Squeak2.6 of 11 October 1999 [latest update: #1559] on 30 November 1999 at 11:07:18 am'!
....SNIP...
I do think that #includes:, if allowed for an interval, should answer true for all values that 'anInterval asArray' includes (or, the equivalent, the set values passed to a #do: block) and false for others. This is not unreasonable and someone else today posted a solution (the same method that's in Collection).
However, it cannot be done with a simple computation. Fudge factors can only make it look right for your test cases. Try this interval with your code:
(1.0e-200 to: 5.0e-200 by: 1.0e-200) asArray => (1.0e-200 2.0e-200 3.0e-200 4.0e-200 5.0e-200 )
Aren't floats fun! :-)
Dave _______________________________ David N. Smith IBM T J Watson Research Center Hawthorne, NY _______________________________ Any opinions or recommendations herein are those of the author and not of his employer.
Aren't floats fun! :-)
No kidding. The introduction of floats causes a problem because there is no unified notion of float comparison in Smalltalk. We might decide, e.g. to use the closeTo: method to determine whether values were in the interval. But, that wouldn't always work as Dave shows. It is clear that at least one author assumed that Intervals had integer values only (see the source for setFrom:to:by:). The only general solution would be to include the fuzz or epsilon value with an instance and defaulting it to some class variable. But there are other instances of comparison (like closeTo: and maybe others) that would not be helped by this solution.
A more complicated, but someone better solution would be to have multiple subclasses of Interval depending on the three values. I think someone else already suggested that.
mkd
At 14:04 -0600 11/30/99, Michael Donegan wrote:
Aren't floats fun! :-)
No kidding. The introduction of floats causes a problem because there is no unified notion of float comparison in Smalltalk.
It is *not* a Smalltalk problem. There is no way to compare floats for equality that does not fail because of base conversion or computational error problems.
It's one of the basic rules of nature:
Never compare two floats for equality.
It right up there with "Don't tug on Superman's cape".
Some languages have introduced the concept of ~fuzz~ for comparisons, but that IMHO is simply a way to encourage people to use floats without understanding them.
Besides, how big is the ~fuzz~? Would it allow intervals like this to work?
(1.0e-200 to: 5.0e-200 by: 0.5e-200)
or would a ~fuzz~ of 1.0e-15 overwhelm the #to: value in the interval? Would it solve problems when the exponents are huge:
(1.0e200 to: 5.0e200 by 0.5e200)
In comparison to 1.0e200, a fixed fuzz value of 1.0e-15 or whatever makes no difference at all.
Floats have a wide range for exponents on purpose; they do get used. If you want the diameter of an electron in centimeters you don't do it without very small exponents. If you want the diameter of the universe in meters you don't do it without very large exponents.
Note that FORTRAN, the most widely used scientific and engineering programming language (80% or more of the market) does not have ~fuzz~. There is no reason why Smalltalk needs it either.
Dave
(BTW, ~fuzz~ is simply a way to make the word fuzz look fuzzy?) _______________________________ David N. Smith IBM T J Watson Research Center Hawthorne, NY _______________________________ Any opinions or recommendations herein are those of the author and not of his employer.
I agree with your (Dave's) analysis of fuzz. APL had it, but one global fuzz could never work for every case. Certainly adjusting the fuzz until things work is no replacement for actually analyzing the problem.
It seems like the 1e-10 is suspect in the current proposed Interval code. It is about as arbitrary as the 0.0001 in the Float#closeTo: code. And maybe worse than having a global fuzz defined. That's why I like the idea of having this "precision" as an instance variable of Interval or possibly a method that can be overridden in some special-purpose subclass.
mkd
squeak-dev@lists.squeakfoundation.org