Skip to content

Commit

Permalink
Merge pull request #9650 from stevengj/cumsum_pairwise
Browse files Browse the repository at this point in the history
get pairwise-sum accuracy for cumsum (fix #9648)
  • Loading branch information
stevengj committed Jan 7, 2015
2 parents d74d8cc + c7c89a4 commit 3de4d53
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 9 deletions.
22 changes: 13 additions & 9 deletions base/array.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1455,20 +1455,24 @@ symdiff(a, b, rest...) = symdiff(a, symdiff(b, rest...))
_cumsum_type{T<:Number}(v::AbstractArray{T}) = typeof(+zero(T))
_cumsum_type(v) = typeof(v[1]+v[1])

for (f, fp, op) = ((:cumsum, :cumsum_pairwise, :+),
(:cumprod, :cumprod_pairwise, :*) )
# in-place cumsum of c = s+v(i1:n), using pairwise summation as for sum
@eval function ($fp)(v::AbstractVector, c::AbstractVector, s, i1, n)
for (f, fp, op) = ((:cumsum, :cumsum_pairwise!, :+),
(:cumprod, :cumprod_pairwise!, :*) )
# in-place cumsum of c = s+v[range(i1,n)], using pairwise summation
@eval function ($fp){T}(v::AbstractVector, c::AbstractVector{T}, s, i1, n)
local s_::T # for sum(v[range(i1,n)]), i.e. sum without s
if n < 128
@inbounds c[i1] = ($op)(s, v[i1])
@inbounds s_ = v[i1]
@inbounds c[i1] = ($op)(s, s_)
for i = i1+1:i1+n-1
@inbounds c[i] = $(op)(c[i-1], v[i])
@inbounds s_ = $(op)(s_, v[i])
@inbounds c[i] = $(op)(s, s_)
end
else
n2 = div(n,2)
($fp)(v, c, s, i1, n2)
($fp)(v, c, c[(i1+n2)-1], i1+n2, n-n2)
n2 = n >> 1
s_ = ($fp)(v, c, s, i1, n2)
s_ = $(op)(s_, ($fp)(v, c, s + s_, i1+n2, n-n2))
end
return s_
end

@eval function ($f)(v::AbstractVector)
Expand Down
5 changes: 5 additions & 0 deletions test/arrayops.jl
Original file line number Diff line number Diff line change
Expand Up @@ -974,3 +974,8 @@ a = [ [ 1 0 0 ], [ 0 0 0 ] ]
@test rotl90(a,4) == a
@test rotr90(a,4) == a
@test rot180(a,2) == a

# issue #9648
let x = fill(1.5f0, 10^7)
@test abs(1.5f7 - cumsum(x)[end]) < 3*eps(1.5f7)
end

0 comments on commit 3de4d53

Please sign in to comment.