FloatRange: new type for accurate floating-point ranges [fix #2333]

This algorithm for floating-point ranges magically reads your mind.

1. It defaults to the plain `[ r.start + k*r.step for k = 0:r.len ]` behavior by setting `len = s` and `divisor = 1`.
2. It attempts to "lift" the iteration to a level where the step is integral by rationalizing `s`, using a customized rationalize function.
3. If the lifted form matches the original `(start,step,stop)` tuple, then we use lifted iteration, stepping by an integer amount and projecting back down to get a perfect floating point range. Otherwise, it falls through to the default behavior.
4. Once the `FloatRange` parameters are determined, iteration and indexing are quite simple: the values of the range are `[ (r.start + k*r.step)/r.divisor for k = 0:r.len ]`.