Interval indexOf:startingAt: is fuzzy

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

Interval indexOf:startingAt: is fuzzy

Nicolas Cellier
Hi,
does anyone really need a fuzzy Interval indexOf:startingAt: ?
Right now, we have this:

    ((0.1 to: 0.9 by: 0.1) indexOf: 0.3) = 3.
    ((0.1 to: 0.9 by: 0.1) includes: 0.3) = true.

While this can sound nice, I don't think it is.
No other collection behaves like that.

    ((0.1 to: 0.9 by: 0.1) asArray includes: 0.3) = false.
    ((0.1 to: 0.9 by: 0.1) asSet includes: 0.3) = false.

Even Interval itself does not behave consitently:

    ((0.1 to: 0.9 by: 0.1) lastIndexOf: 0.3) = 0.
    ((0.1 to: 0.9 by: 0.1) occurrencesOf: 0.3) = 0.
    ((0.1 to: 0.9 by: 0.1) copyWithout: 0.3) = #(0.1 0.2 0.30000000000000004 0.4 0.5 0.6 0.7000000000000001 0.8 0.9).

We have ScaledDecimal and Fraction which are less surprising, so IMO we should better use them when we really want to play with equality rather than trying to cheat with Float equality.



Reply | Threaded
Open this post in threaded view
|

Re: Interval indexOf:startingAt: is fuzzy

Nicolas Cellier
Even if http://bugs.squeak.org/view.php?id=6455 example does not fit well with ScaledDecimal/Fraction, that does not make Float expectations more valid.
See #testIndexOfBug6455

   ((0 to: Float pi by: Float pi / 100) indexOf: Float pi * (3/100))

I corrected indexOf:startingAt: myself (because fuzziness wasn't correctly implemented), then Levente provided a better implementation.
But that does not mean that we endorse the feature!

This kind of expectation is void because of nature of Float.
See this, the last element in that example is not even Float pi:

    (0 to: Float pi by: Float pi / 100) last = 3.1101767270538954.

We could instead write something like:

    anglesInDegrees := 0 to: 180 by: 180/100.
    fractionsOfPi := 0 to: 1 by: 1/100.

and have our programs behave well better!

Le dim. 10 févr. 2019 à 15:27, Nicolas Cellier <[hidden email]> a écrit :
Hi,
does anyone really need a fuzzy Interval indexOf:startingAt: ?
Right now, we have this:

    ((0.1 to: 0.9 by: 0.1) indexOf: 0.3) = 3.
    ((0.1 to: 0.9 by: 0.1) includes: 0.3) = true.

While this can sound nice, I don't think it is.
No other collection behaves like that.

    ((0.1 to: 0.9 by: 0.1) asArray includes: 0.3) = false.
    ((0.1 to: 0.9 by: 0.1) asSet includes: 0.3) = false.

Even Interval itself does not behave consitently:

    ((0.1 to: 0.9 by: 0.1) lastIndexOf: 0.3) = 0.
    ((0.1 to: 0.9 by: 0.1) occurrencesOf: 0.3) = 0.
    ((0.1 to: 0.9 by: 0.1) copyWithout: 0.3) = #(0.1 0.2 0.30000000000000004 0.4 0.5 0.6 0.7000000000000001 0.8 0.9).

We have ScaledDecimal and Fraction which are less surprising, so IMO we should better use them when we really want to play with equality rather than trying to cheat with Float equality.



Reply | Threaded
Open this post in threaded view
|

Re: Interval indexOf:startingAt: is fuzzy

Chris Muller-3
In reply to this post by Nicolas Cellier
Like Rectangles, Intervals only support Integers, i.e., see Interval>>#last.


 - Chris

On Sun, Feb 10, 2019 at 8:27 AM Nicolas Cellier
<[hidden email]> wrote:

>
> Hi,
> does anyone really need a fuzzy Interval indexOf:startingAt: ?
> Right now, we have this:
>
>     ((0.1 to: 0.9 by: 0.1) indexOf: 0.3) = 3.
>     ((0.1 to: 0.9 by: 0.1) includes: 0.3) = true.
>
> While this can sound nice, I don't think it is.
> No other collection behaves like that.
>
>     ((0.1 to: 0.9 by: 0.1) asArray includes: 0.3) = false.
>     ((0.1 to: 0.9 by: 0.1) asSet includes: 0.3) = false.
>
> Even Interval itself does not behave consitently:
>
>     ((0.1 to: 0.9 by: 0.1) lastIndexOf: 0.3) = 0.
>     ((0.1 to: 0.9 by: 0.1) occurrencesOf: 0.3) = 0.
>     ((0.1 to: 0.9 by: 0.1) copyWithout: 0.3) = #(0.1 0.2 0.30000000000000004 0.4 0.5 0.6 0.7000000000000001 0.8 0.9).
>
> We have ScaledDecimal and Fraction which are less surprising, so IMO we should better use them when we really want to play with equality rather than trying to cheat with Float equality.
>
>

Reply | Threaded
Open this post in threaded view
|

Re: Interval indexOf:startingAt: is fuzzy

Eliot Miranda-2
In reply to this post by Nicolas Cellier


_,,,^..^,,,_ (phone)

On Feb 10, 2019, at 6:27 AM, Nicolas Cellier <[hidden email]> wrote:

Hi,
does anyone really need a fuzzy Interval indexOf:startingAt: ?
Right now, we have this:

    ((0.1 to: 0.9 by: 0.1) indexOf: 0.3) = 3.
    ((0.1 to: 0.9 by: 0.1) includes: 0.3) = true.

While this can sound nice, I don't think it is.
No other collection behaves like that.

    ((0.1 to: 0.9 by: 0.1) asArray includes: 0.3) = false.
    ((0.1 to: 0.9 by: 0.1) asSet includes: 0.3) = false.


What if instead we added a range numeric type?  Then we could write something like

((0.1 to: 0.9 by: 0.1) asArray includes: (0.3 plusOrMinus: 0.001)) = true.

NumericRange would be instantiated via plusOrMinus: & from:to:, and implement interval arithmetic and interval comparison.  So = would be

= aMagnitude
    ^aMagnitude between: start and stop

and NumericRange would itself use its midpoint for comparisons against magnitudes.  It would presumably not be a magnitude itself though, so that two NumericRanges would be equal only if they represented the same range, not had the same midpoint.


Even Interval itself does not behave consitently:

    ((0.1 to: 0.9 by: 0.1) lastIndexOf: 0.3) = 0.
    ((0.1 to: 0.9 by: 0.1) occurrencesOf: 0.3) = 0.
    ((0.1 to: 0.9 by: 0.1) copyWithout: 0.3) = #(0.1 0.2 0.30000000000000004 0.4 0.5 0.6 0.7000000000000001 0.8 0.9).

We have ScaledDecimal and Fraction which are less surprising, so IMO we should better use them when we really want to play with equality rather than trying to cheat with Float equality.




Reply | Threaded
Open this post in threaded view
|

Re: Interval indexOf:startingAt: is fuzzy

Nicolas Cellier


Le dim. 10 févr. 2019 à 20:16, Eliot Miranda <[hidden email]> a écrit :


_,,,^..^,,,_ (phone)

On Feb 10, 2019, at 6:27 AM, Nicolas Cellier <[hidden email]> wrote:

Hi,
does anyone really need a fuzzy Interval indexOf:startingAt: ?
Right now, we have this:

    ((0.1 to: 0.9 by: 0.1) indexOf: 0.3) = 3.
    ((0.1 to: 0.9 by: 0.1) includes: 0.3) = true.

While this can sound nice, I don't think it is.
No other collection behaves like that.

    ((0.1 to: 0.9 by: 0.1) asArray includes: 0.3) = false.
    ((0.1 to: 0.9 by: 0.1) asSet includes: 0.3) = false.


What if instead we added a range numeric type?  Then we could write something like

((0.1 to: 0.9 by: 0.1) asArray includes: (0.3 plusOrMinus: 0.001)) = true.

You can even use a nice binary operator 0.3 +/- 0.001 :)


NumericRange would be instantiated via plusOrMinus: & from:to:, and implement interval arithmetic and interval comparison.  So = would be

= aMagnitude
    ^aMagnitude between: start and stop

and NumericRange would itself use its midpoint for comparisons against magnitudes.  It would presumably not be a magnitude itself though, so that two NumericRanges would be equal only if they represented the same range, not had the same midpoint.

All these solutions make = not transitive...
    a = b && (b = c) ==> (a = c)

So if we want interval arithmetic we'd rather use another set of selectors for achieving this fuzzyfication...



Even Interval itself does not behave consitently:

    ((0.1 to: 0.9 by: 0.1) lastIndexOf: 0.3) = 0.
    ((0.1 to: 0.9 by: 0.1) occurrencesOf: 0.3) = 0.
    ((0.1 to: 0.9 by: 0.1) copyWithout: 0.3) = #(0.1 0.2 0.30000000000000004 0.4 0.5 0.6 0.7000000000000001 0.8 0.9).

We have ScaledDecimal and Fraction which are less surprising, so IMO we should better use them when we really want to play with equality rather than trying to cheat with Float equality.





Reply | Threaded
Open this post in threaded view
|

Re: Interval indexOf:startingAt: is fuzzy

Tobias Pape

> On 11.02.2019, at 00:54, Nicolas Cellier <[hidden email]> wrote:
>
>
>
> Le dim. 10 févr. 2019 à 20:16, Eliot Miranda <[hidden email]> a écrit :
>
>
> _,,,^..^,,,_ (phone)
>
> On Feb 10, 2019, at 6:27 AM, Nicolas Cellier <[hidden email]> wrote:
>
>> Hi,
>> does anyone really need a fuzzy Interval indexOf:startingAt: ?
>> Right now, we have this:
>>
>>     ((0.1 to: 0.9 by: 0.1) indexOf: 0.3) = 3.
>>     ((0.1 to: 0.9 by: 0.1) includes: 0.3) = true.
>>
>> While this can sound nice, I don't think it is.
>> No other collection behaves like that.
>>
>>     ((0.1 to: 0.9 by: 0.1) asArray includes: 0.3) = false.
>>     ((0.1 to: 0.9 by: 0.1) asSet includes: 0.3) = false.
>
>
> What if instead we added a range numeric type?  Then we could write something like
>
> ((0.1 to: 0.9 by: 0.1) asArray includes: (0.3 plusOrMinus: 0.001)) = true.
>
> You can even use a nice binary operator 0.3 +/- 0.001 :)

or even ± for that matter :)

>
>
> NumericRange would be instantiated via plusOrMinus: & from:to:, and implement interval arithmetic and interval comparison.  So = would be
>
> = aMagnitude
>     ^aMagnitude between: start and stop
>
> and NumericRange would itself use its midpoint for comparisons against magnitudes.  It would presumably not be a magnitude itself though, so that two NumericRanges would be equal only if they represented the same range, not had the same midpoint.
>
> All these solutions make = not transitive...
>     a = b && (b = c) ==> (a = c)
>
> So if we want interval arithmetic we'd rather use another set of selectors for achieving this fuzzyfication...
>
>
>>
>> Even Interval itself does not behave consitently:
>>
>>     ((0.1 to: 0.9 by: 0.1) lastIndexOf: 0.3) = 0.
>>     ((0.1 to: 0.9 by: 0.1) occurrencesOf: 0.3) = 0.
>>     ((0.1 to: 0.9 by: 0.1) copyWithout: 0.3) = #(0.1 0.2 0.30000000000000004 0.4 0.5 0.6 0.7000000000000001 0.8 0.9).
>>
>> We have ScaledDecimal and Fraction which are less surprising, so IMO we should better use them when we really want to play with equality rather than trying to cheat with Float equality.