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

revert linspace to creating a vector #18492

Closed
StefanKarpinski opened this issue Sep 13, 2016 · 10 comments
Closed

revert linspace to creating a vector #18492

StefanKarpinski opened this issue Sep 13, 2016 · 10 comments
Assignees
Labels
speculative Whether the change will be implemented is speculative
Milestone

Comments

@StefanKarpinski
Copy link
Sponsor Member

See #14420 and various other issues. It seems best to remove the LinSpace type from Base and move it to a package, keeping the linspace function but having it just return a vector of values.

@StefanKarpinski StefanKarpinski added the speculative Whether the change will be implemented is speculative label Sep 13, 2016
@tkelman
Copy link
Contributor

tkelman commented Sep 14, 2016

We already have several spellings for getting the linspace result as a vector, either collect or an equivalent comprehension. We wouldn't have a spelling for getting the lightweight iterator object of a range with exact start, end, and number of items if we did this. Tim's suggestion at #17408 (comment) for simplifying its behavior seemed popular so far.

@StefanKarpinski
Copy link
Sponsor Member Author

That was originally my thinking as well, but currently we don't have an easy spelling for getting linspace result as a vector with always correct end-points.

@StefanKarpinski
Copy link
Sponsor Member Author

I.e. #14420. @timholy's suggestion is certainly appealingly simple, but it really whiffs on a huge number of cases for internal points. I really don't think it makes sense to have this type and have it return half-baked results. Especially when the FloatRange behavior would actually be what one wants in those same cases.

@mbauman
Copy link
Sponsor Member

mbauman commented Sep 14, 2016

I disagree. If you care about the steps looking right, use the syntax that specifies a step. If you care about the number of elements and final endpoint, use the syntax that specifies those.

They're different algorithms. With different spellings. The only thing I'd change about Tim's implementation is how it prints itself; it should look different from a FloatRange, because it is.

Let's keep it as a lazy type. Folks are going to get more accustomed to all the specialized array types as we start using them more. And support for BLAS-incompatible array types is only getting better.

@StefanKarpinski StefanKarpinski added this to the 0.6.0 milestone Sep 14, 2016
@StefanKarpinski
Copy link
Sponsor Member Author

export broken_linspace and correct_linspace? :P

@timholy
Copy link
Sponsor Member

timholy commented Sep 14, 2016

I think my brain spends 10% of its cycles running @test_approx_eq_eps x y factor_of_two, so when I look at 0.3 and 0.299999999 I have to rub my eyes thrice to even notice that there's a difference.

Jokes aside, I do think there's a legitimate issue of whether it's really worth calling such differences "broken." As you yourself have pointed out, there are limits to representing mathematical quantities with a finite number of bits.

@eschnett
Copy link
Contributor

IEEE goes to great lengths to specify that addition, multiplication, and a few other operations need to be calculated correctly up to the last bit. With @fastmath, I like to take shortcuts, but without, I expect all the precision I can get.

linspace is mentally a sufficiently simple operation that it should work without rounding error.

@StefanKarpinski
Copy link
Sponsor Member Author

... and for that you need do use the division operator.

@timholy
Copy link
Sponsor Member

timholy commented Sep 25, 2016

Referencing #17408 (comment), this version seems likely to get it essentially perfect:

function Base.getindex(r::NewLinSpace, i::Integer)
    d = r.len-1
    s1 = fraction(r.len-i, r.leninv, d)
    s2 = fraction(i-1,     r.leninv, d)
    s1*r.start + s2*r.stop
end

@inline function fraction(k, dinv, d)
    x = k*dinv
    x + (k-x*d)*dinv
end

The only problem is it's 50% slower than our current LinSpace on a sum-over-all entries benchmark (eliding boundschecks). Perhaps there's something clever we could do to speed this up?

@StefanKarpinski
Copy link
Sponsor Member Author

Closed in favor of #18777.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
speculative Whether the change will be implemented is speculative
Projects
None yet
Development

No branches or pull requests

5 participants