diff --git a/NEWS.md b/NEWS.md index 4c976a14783cc..9bfb778f317b5 100644 --- a/NEWS.md +++ b/NEWS.md @@ -79,7 +79,7 @@ Library improvements * Arithmetic is type-preserving for more types; e.g. `(x::Int8) + (y::Int8)` now yields an `Int8` ([#3759]). - * Reductions (e.g. `reduce`, `sum`) widen small types (integers smaller than `Int`, and `Float16`). + * Reductions (e.g. `reduce`, `sum`) widen small types (integers smaller than `Int`, and `Float16`). Similarly for `cumsum` ([#9665]). * New `Dates` module for calendar dates and other time-interval calculations ([#7654]). @@ -1149,5 +1149,8 @@ Too numerous to mention. [#9261]: https://github.com/JuliaLang/julia/issues/9261 [#9271]: https://github.com/JuliaLang/julia/issues/9271 [#9294]: https://github.com/JuliaLang/julia/issues/9294 -[#9569]: https://github.com/JuliaLang/julia/issues/9569 +[#9418]: https://github.com/JuliaLang/julia/issues/9418 [#9452]: https://github.com/JuliaLang/julia/issues/9452 +[#9569]: https://github.com/JuliaLang/julia/issues/9569 +[#9578]: https://github.com/JuliaLang/julia/issues/9578 +[#9665]: https://github.com/JuliaLang/julia/issues/9665 diff --git a/base/array.jl b/base/array.jl index 514aae76957ae..56136bde631e8 100644 --- a/base/array.jl +++ b/base/array.jl @@ -1452,11 +1452,11 @@ symdiff(a) = a symdiff(a, b) = union(setdiff(a,b), setdiff(b,a)) 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]) +_cumsum_type{T<:Number}(v::AbstractArray{T}) = typeof(r_promote(AddFun, zero(T)::T)) +_cumsum_type(v) = typeof(r_promote(AddFun, v[1])) -for (f, fp, op) = ((:cumsum, :cumsum_pairwise!, :+), - (:cumprod, :cumprod_pairwise!, :*) ) +for (f, f!, fp, op) = ((:cumsum, :cumsum!, :cumsum_pairwise!, :+), + (:cumprod, :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 @@ -1475,16 +1475,18 @@ for (f, fp, op) = ((:cumsum, :cumsum_pairwise!, :+), return s_ end - @eval function ($f)(v::AbstractVector) + @eval function ($f!)(result::AbstractVector, v::AbstractVector) n = length(v) + if n == 0; return result; end + ($fp)(v, result, $(op==:+ ? :(zero(v[1])) : :(one(v[1]))), 1, n) + return result + end + + @eval function ($f)(v::AbstractVector) c = $(op===:+ ? (:(similar(v,_cumsum_type(v)))) : (:(similar(v)))) - if n == 0; return c; end - ($fp)(v, c, $(op==:+ ? :(zero(v[1])) : :(one(v[1]))), 1, n) - return c + return ($f!)(c, v) end - - @eval ($f)(A::AbstractArray) = ($f)(A, 1) end for (f, op) = ((:cummin, :min), (:cummax, :max)) diff --git a/test/arrayops.jl b/test/arrayops.jl index c6e1bcc5da77d..09d4f2e5ad873 100644 --- a/test/arrayops.jl +++ b/test/arrayops.jl @@ -978,4 +978,11 @@ a = [ [ 1 0 0 ], [ 0 0 0 ] ] # issue #9648 let x = fill(1.5f0, 10^7) @test abs(1.5f7 - cumsum(x)[end]) < 3*eps(1.5f7) + @test cumsum(x) == cumsum!(similar(x), x) +end + +# cumsum type consistency (discussed in #9650) +let x = Uint8[1,2,3,4,6,7] + @test eltype(cumsum(x)) == typeof(sum(x)) == eltype(cumsum(reshape(x,3,2))) + @test cumsum(x) == cumsum!(similar(x),x) == cumsum!(similar(x,Int), x) end