Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

linrange for constructing ranges by endpoints and length #6627

Merged
merged 3 commits into from
Jun 28, 2014

Conversation

simonbyrne
Copy link
Contributor

julia> linrange(0,pi,100)
0.0:0.03173325912716963:3.141592653589793

@simonbyrne
Copy link
Contributor Author

I should also mention that I'm open to better names for this.

@jasongrout
Copy link

Just as a data point, a numpy-inspired syntax would be something like 0:100im:pi, where a complex step size indicates a number of points rather than a step size.

@jiahao
Copy link
Member

jiahao commented Apr 24, 2014

Using im in this idiosyncratic fashion is very much not in the Julia style.

@jasongrout
Copy link

I don't like it too much myself. Just mentioning it for completeness.

@JeffBezanson
Copy link
Member

This should handle the len==1 case.
Other than that, seems ok to me. Any opinion @StefanKarpinski ?

@StefanKarpinski
Copy link
Member

Wasn't this what the range function was supposed to do?

@JeffBezanson
Copy link
Member

range accepts start, step, length, this accepts start, end, length. I know, seems to be asking for keyword arguments, but I'm not sure default values can express what's needed.

@StefanKarpinski
Copy link
Member

Wait, range accepts start, step and length? Why not start, stop and length?

@JeffBezanson
Copy link
Member

Yes. Sometimes start, step, length is useful, mostly for implementing range arithmetic.

@simonbyrne
Copy link
Contributor Author

It occurs to me there are multiple ways this could be implemented:

linrange1(a,b,len) = range(a, (b-a)/(len-1),len) # current implementation: 1.0 as the denominator
linrange2(a,b,len) = FloatRange(a*(len-1), b-a, float(len), float(len-1)) # use len-1 as the denominator
linrange3(a,b,len) = colon(a,(b-a)/(len-1),b) # use rationalisation
julia> Base.showcompact(io::IO, x::Float64) = show(io,x)

julia> [linrange1(0.3,1.1,9) linrange2(0.3,1.1,9) linrange3(0.3,1.1,9)]
9x3 Array{Float64,2}:
 0.3                 0.3                 0.3
 0.4                 0.4                 0.4
 0.5                 0.5                 0.5
 0.6000000000000001  0.6000000000000001  0.6
 0.7                 0.7                 0.7
 0.8                 0.8                 0.8
 0.9000000000000001  0.9000000000000001  0.9
 1.0                 1.0                 1.0
 1.1                 1.1                 1.1

# for reference:
julia> [linspace(0.3,1.1,9) float64(linspace(big(0.3),1.1,9))]
9x2 Array{Float64,2}:
 0.3                 0.3               
 0.4                 0.4               
 0.5                 0.5               
 0.6000000000000001  0.6               
 0.7000000000000001  0.7000000000000001
 0.8                 0.8               
 0.9                 0.9               
 1.0000000000000002  1.0               
 1.1                 1.1               

@mbauman
Copy link
Member

mbauman commented Jun 24, 2014

Bump. I just ran into a case where I'd like to use this. With regards to the three possible implementations, it seems to me that there are a few properties that are essential:

  1. It must have exactly len elements. This is the reason for this function to exist.
  2. It should of course start at exactly a, and I think it'd be best for the last element to always be less than or equal to b. This isn't as important, however.

So I did some very simplistic fuzz testing of these implementations. linrange3 breaks property 1 about 5% of the time with those parameters, so I think that implementation is out.

The other two implementations seem to be fairly comparable. They both break property 2 about 5% of the time, but are always within eps(last). That may be good enough. I'm not sure if there's another distinguishing test that would favor one for the other.

@simonbyrne
Copy link
Contributor Author

Thanks @mbauman. I've kept the current behaviour, as that seems the simplest, and added the handling for len=1, and a couple of tests. Should be good to go.

@@ -157,6 +157,8 @@ range(a::FloatingPoint, st::FloatingPoint, len::Integer) = FloatRange(a,st,len,o
range(a::Real, st::FloatingPoint, len::Integer) = FloatRange(float(a), st, len, one(st))
range(a::FloatingPoint, st::Real, len::Integer) = FloatRange(a, float(st), len, one(a))

linrange(a::Real,b::Real,len::Integer) = len >= 2 ? range(a, (b-a)/(len-1),len) : len == 1 && a == b ? range(a, zero(a), 1) : error("invalid range length")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should use zero((b-a)/(len-1)) instead of zero(a).

@simonbyrne
Copy link
Contributor Author

This should be good to go: it would be great to have this in 0.3...

JeffBezanson added a commit that referenced this pull request Jun 28, 2014
`linrange` for constructing ranges by endpoints and length
@JeffBezanson JeffBezanson merged commit 70b6680 into JuliaLang:master Jun 28, 2014
@simonbyrne simonbyrne deleted the linrange branch March 10, 2015 12:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants