Closed gnzlbg closed 7 years ago
For the naming and calling conventions discussion, in R it's called seq
and is typically called by seq(from=...,to=...,by=...)
or seq(from=...,to=...,length=...)
.
Does
ints(0.5, 5.5)
return a range of doubles [0.5, 5.5) that is incremented by 1.0 ?
Have you tried it?
If so, then the name
ints
is a bit misleading and otherwise, why not?
view::ints
requires Integral, so no, it does not work. view::iota
has looser constraints; view::iota(x)
requires only Incrementable, and view::iota(x,y)
adds EqualityComparable. But comparing doubles using op== is very bad. view::iota(0.0,5.0)
is wrong given the current implementation. view::iota(0.0) | view::take(5)
works though. I need to think about this.
I'm ambivalent about added stride arguments to iota
and ints
. That's what view::stride
is for.
view::iota(x) requires only Incrementable, and view::iota(x,y) adds EqualityComparable.
Thinking about it, are floats/doubles EqualityComparable or just "less than comparable"?
I'm ambivalent about added stride arguments to iota and ints. That's what view::stride is for.
It is not required at all, but I think it is a nice-to-have sugar.
On Mon, Jan 26, 2015 at 6:32 AM, Eric Niebler notifications@github.com wrote:
Does ints(0.5, 5.5) return a range of doubles [0.5, 5.5) that is incremented by 1.0 ?
Have you tried it?
If so, then the name ints is a bit misleading and otherwise, why not?
view::ints requires Integral, so no, it does not work. view::iota has looser constraints; view::iota(x) requires only Incrementable, and view::iota(x,y) adds EqualityComparable. But comparing doubles using op== is very bad. view::iota(0.0,5.0) is wrong given the current implementation. view::iota(0.0) | view::take(5) works though. I need to think about this.
I'm ambivalent about added stride arguments to iota and ints. That's what view::stride is for.
— Reply to this email directly or view it on GitHub https://github.com/ericniebler/range-v3/issues/102#issuecomment-71416402 .
For many uses, a more natural way to specify a numeric range is to specify an integral number of steps between two values rather than the actual increment. There are many ways to deal with the error at each step, two common ways are error accumulation and stochastic rounding. A simple method of error accumulation is to subtract off each segment and re-divide the remaining part into the remaining number of segments. This works for both floating point and integral values (it is precision agnostic). You can use the same approach with a non integral number of steps - though for sequence algorithms it is an odd notion (i.e., divide this range into 3 1/2 pieces).
On Sun, Jan 25, 2015 at 9:32 PM, Eric Niebler notifications@github.com wrote:
Does ints(0.5, 5.5) return a range of doubles [0.5, 5.5) that is incremented by 1.0 ?
Have you tried it?
If so, then the name ints is a bit misleading and otherwise, why not?
view::ints requires Integral, so no, it does not work. view::iota has looser constraints; view::iota(x) requires only Incrementable, and view::iota(x,y) adds EqualityComparable. But comparing doubles using op== is very bad. view::iota(0.0,5.0) is wrong given the current implementation. view::iota(0.0) | view::take(5) works though. I need to think about this.
I'm ambivalent about added stride arguments to iota and ints. That's what view::stride is for.
— Reply to this email directly or view it on GitHub https://github.com/ericniebler/range-v3/issues/102#issuecomment-71416402 .
For many uses, a more natural way to specify a numeric range is to specify an integral number of steps between two values rather than the actual increment.
I'll take your word for it, but I've never wanted to specify a numeric range that way.
There are many ways to deal with the error at each step, two common ways are error accumulation and stochastic rounding. A simple method of error accumulation is to subtract off each segment and re-divide the remaining part into the remaining number of segments. This works for both floating point and integral values (it is precision agnostic).
Interesting! But integral division is horribly slow, so you wouldn't want to do it this way for ints. Also, it doesn't work for all Incrementable types; e.g., iterators.
The existing interface is convenient for many uses and is efficient, but dangerous with floating point types. Those should probably be disallowed (or a safer implementation selected), and an interface like you suggest be provided for numeric Incrementable types, floats included -- and an optimized implementation selected for for integral types and other Incrementables like iterators.
What to call this view?
For many uses, a more natural way to specify a numeric range is to specify an integral number of steps between two values rather than the actual increment.
I'll take your word for it, but I've never wanted to specify a numeric range that way.
This is extremely common in Matlab, where the function is called linspace
(docs here) and used all the time, however it is a bit weird.
Generate linearly spaced vector The linspace function generates linearly spaced vectors. It is similar to the colon operator ":" but gives direct control over the number of points and always includes the endpoints.
Since:
N
points, N
is 1
, then linspace
returns end
. In a recent interview, Stepanov says he wanted to name iterators
linear coordinates
instead, my mind made a connection here, but it is not the same thing, I like the name linear tho.
I think the name linspace
in matlab comes from specifying a line, with two end points, and getting a range of points in the line. In this context, [begin, end] makes sense, and if you specify N
to be 1, and begin
to be 0
, then returning end
makes sense, since your line goes through zero, and what you get is the vector from 0
to end
, which is just end
.
Anyhow, I would find such a view useful, and view::linear
could be a nice name.
Interesting! But integral division is horribly slow, so you wouldn't want to do it this way for ints. Also, it doesn't work for all Incrementable types; e.g., iterators.
The existing interface is convenient for many uses and is efficient, but dangerous with floating point types. Those should probably be disallowed (or a safer implementation selected), and an interface like you suggest be provided for numeric Incrementable types, floats included -- and an optimized implementation selected for for integral types and other Incrementables like iterators.
Agreed, sounds like the best way to do it.
What to call this view?
I like view::linear
, makes sense for iterators, ints, floats, complex numbers...
What about the semantics?
Yes, it is also widely used in R, for example when producing a set of x-coordinates to be used when plotting (as in xs=seq(x_min, x_max, length=length); ys=f(xs); plot(xs,ys)
).
On Wed, Jan 28, 2015 at 8:51 PM, Eric Niebler notifications@github.com wrote:
For many uses, a more natural way to specify a numeric range is to specify an integral number of steps between two values rather than the actual increment.
I'll take your word for it, but I've never wanted to specify a numeric range that way.
You probably have, you just didn't have a name for it or know it.
There are many ways to deal with the error at each step, two common ways are error accumulation and stochastic rounding. A simple method of error accumulation is to subtract off each segment and re-divide the remaining part into the remaining number of segments. This works for both floating point and integral values (it is precision agnostic).
Interesting! But integral division is horribly slow, so you wouldn't want to do it this way for ints. Also, it doesn't work for all Incrementable types; e.g., iterators.
It works for any forward incrementable type. Anything that can be transformed to a counted range.
Any time you write a recursive subdivision algorithm you likely operate on halves of length n / 2, and n - n / 2. That is the equivalent (using matlab terminology) linspace(first, last, 2). If you want to divide work for m-cores you would replace 2 with m...
Of course integer division is slow - this is why you forward difference and you get Bresenham's algorithm (useful for drawing lines as well - it is the same problem).
The existing interface is convenient for many uses and is efficient, but
dangerous with floating point types. Those should probably be disallowed (or a safer implementation selected), and an interface like you suggest be provided for numeric types, floats included -- and an optimized implementation selected for for integral types and other Incrementables like iterators.
What to call this view?
Good question - linear_spaced()? distribute()? linear_distribute()? [There are other distributions possible for the points - just as a linear distribution is equivalent to plotting a line you could have other distributions that would be the equivalent of curves. Though usually if you just say you distributing a set of points the assumption is linear unless stated otherwise.]
Sean
— Reply to this email directly or view it on GitHub https://github.com/ericniebler/range-v3/issues/102#issuecomment-71968995 .
For what it's worth, I've been using the range library for a few months, and have occasionally needed the function described here. Python's numpy
also has linspace which permits endpoint control, while xrange
has simpler behavior and is like range-v3's views.
I like the idea of calling it uniform_step
or linear_step
. linear
seems too broad, as I can imagine other interesting linear ranges which aren't uniformly spaced points.
Nate
All the proposed functions are inclusive and a superset of ints(from, to)
, so I don't know how much sense it makes to have two different views for creating an inclusive range with a step; ints
just uses a step of 1
and works only for Integral
s (I think that for ints
to be an inclusive range is unfortunate).
If the name linear
is too general, I'd stick to something similar to Matlab's linspace
, Sean's linear_spaced
seems a good suggestion to me.
Does
ints(0.5, 5.5)
return a range of doubles [0.5, 5.5) that is incremented by 1.0 ?If so, then the name
ints
is a bit misleading and otherwise, why not?Both python
xrange
and D'siota
support a step or a stride, as well as integers and floating point, so I think that this common case deserves some syntax sugar for creating [from, to) strided ranges.A solution to this could be to offer both, an
integer_range
and anumeric_range
. The numeric range could have the stride bolted in (I don't thinkview::strided
can or should be made to work withnumeric
strides). Thenumeric_range
could use by defaulta < b && a > b
as implementation fora != b
but this should probably be customizable.Then something like:
range(0, 1)
returns aninteger_range
,range(0, 4, 2)
returns an strided view of an integer range, andrange(0.0, 5.0, 1.0)
returns anumeric_range
.(TODO: replace
range
with a better name).