Added Within function.

Within is useful for finding the bin of a datapoint, for example when making a histogram or otherwise trying to find similar points. This commit adds the function and tests.

On Oct 12, 2014, at 3:28 PM, Dan Kortschak <notifications@github.com> wrote:

> In floats.go:
> 
> > @@ -655,3 +655,32 @@ func Sum(s []float64) float64 {
> >  	}
> >  	return sum
> >  }
> > +
> > +// Within returns the first index i where s[i] <= v < s[i+1]. As a special case, Within
> > +// returns len(s)-1 if v == s[len(s)-1]. Within can be useful for binning data
> > +// in non-uniform grids. Within panics if:
> > +// - len(s) < 2
> > +// - s is not sorted
> > +// - v is NaN
> > +// - v < s[0]
> > +// - v > s[len(s)-1]
> According to the implementation as I see it, you don't need to add a NextAfter, you just need to duplicate the max item. This may seem ugly, but I don't see it as any less ugly than changing the way the coordinate system works at a boundary.
> 

I agree with your interpretation, but I think it’s way uglier to do as you suggest. Loosely, the function means “Return the index where this value is between the two values in the bins”. Unfortunately, we have to consider the case of exactly matching one of the bins. 

It seems to me that there’s nothing special about the low end or the high end, and so the function should be symmetric, and thus it should behave as (min,max) or [min,max]. For uses of this function with real data, exact matches on the middle boundaries should be rare or non-existant, otherwise this function is meaningless. However, matching on the very ends may be common due to minimum and maximum possible values.

One solution is to provide an additional option on how to treat the boundaries.

func Within(s []float64, v float64, w WithinFlag) int

type WitihinFlag int

const(
    Exclusive           // return -1 if the value lies exactly on any of the bounds
    InclusiveLower WithinFlag = iota // treat the bounds as inclusive, round to the lower bin
    InclusiveUpper 
    SemiInclusiveLower    // round to the lower bin, treated as [min,max)
    SemiInclusiveUpper
)

Comments need to be improved, but you get the idea.=