Skip to content

Commit 2553673

Browse files
committed
simplify sum, prod behaviour
1 parent df2820a commit 2553673

File tree

1 file changed

+41
-29
lines changed

1 file changed

+41
-29
lines changed

base/reduce.jl

Lines changed: 41 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,13 @@ end
1515
# Certain reductions like sum and prod may wish to promote the items being reduced over to
1616
# an appropriate size. Note we need x + zero(x) because some types like Bool have their sum
1717
# lie in a larger type.
18-
promote_sys_size(T::Type) = T
19-
promote_sys_size(::Type{<:SmallSigned}) = Int
20-
promote_sys_size(::Type{<:SmallUnsigned}) = UInt
18+
add_tosys(x,y) = x + y
19+
add_tosys(x::SmallSigned,y::SmallSigned) = Int(x) + Int(y)
20+
add_tosys(x::SmallUnsigned,y::SmallUnsigned) = UInt(x) + UInt(y)
2121

22-
promote_sys_size_add(x) = convert(promote_sys_size(typeof(x + zero(x))), x)
23-
promote_sys_size_mul(x) = convert(promote_sys_size(typeof(x * one(x))), x)
24-
const _PromoteSysSizeFunction = Union{typeof(promote_sys_size_add),
25-
typeof(promote_sys_size_mul)}
22+
mul_tosys(x,y) = x * y
23+
mul_tosys(x::SmallSigned,y::SmallSigned) = Int(x) * Int(y)
24+
mul_tosys(x::SmallUnsigned,y::SmallUnsigned) = UInt(x) * UInt(y)
2625

2726
## foldl && mapfoldl
2827

@@ -253,6 +252,12 @@ reduce_empty(::typeof(*), T) = one(T)
253252
reduce_empty(::typeof(&), ::Type{Bool}) = true
254253
reduce_empty(::typeof(|), ::Type{Bool}) = false
255254

255+
reduce_empty(::typeof(add_tosys), T) = zero(T)
256+
reduce_empty(::typeof(add_tosys), ::Type{T}) where {T<:SmallSigned} = zero(Int)
257+
reduce_empty(::typeof(add_tosys), ::Type{T}) where {T<:SmallUnsigned} = zero(UInt)
258+
reduce_empty(::typeof(mul_tosys), T) = one(T)
259+
reduce_empty(::typeof(mul_tosys), ::Type{T}) where {T<:SmallSigned} = one(Int)
260+
reduce_empty(::typeof(mul_tosys), ::Type{T}) where {T<:SmallUnsigned} = one(UInt)
256261

257262
"""
258263
Base.mapreduce_empty(f, op, T)
@@ -263,37 +268,44 @@ array with element type of `T`.
263268
If not defined, this will throw an `ArgumentError`.
264269
"""
265270
mapreduce_empty(f, op, T) = _empty_reduce_error()
266-
mapreduce_empty(::typeof(identity), op, T) = reduce_empty(op, T)
267-
mapreduce_empty(f::_PromoteSysSizeFunction, op, T) =
268-
f(mapreduce_empty(identity, op, T))
269-
mapreduce_empty(::typeof(abs), ::typeof(+), T) = abs(zero(T))
270-
mapreduce_empty(::typeof(abs2), ::typeof(+), T) = abs2(zero(T))
271-
mapreduce_empty(::typeof(abs), ::Union{typeof(scalarmax), typeof(max)}, T) =
272-
abs(zero(T))
273-
mapreduce_empty(::typeof(abs2), ::Union{typeof(scalarmax), typeof(max)}, T) =
274-
abs2(zero(T))
275-
276-
# Allow mapreduce_empty to “see through” promote_sys_size
277-
let ComposedFunction = typename(typeof(identity identity)).wrapper
278-
global mapreduce_empty(f::ComposedFunction{<:_PromoteSysSizeFunction}, op, T) =
279-
f.f(mapreduce_empty(f.g, op, T))
280-
end
271+
mapreduce_empty(f::typeof(identity), op, T) = f(reduce_empty(op, T))
272+
mapreduce_empty(f::typeof(abs), op, T) = f(reduce_empty(op, T))
273+
mapreduce_empty(f::typeof(abs2), op, T) = f(reduce_empty(op, T))
274+
275+
mapreduce_empty(f::typeof(abs), ::Union{typeof(scalarmax), typeof(max)}, T) = abs(zero(T))
276+
mapreduce_empty(f::typeof(abs2), ::Union{typeof(scalarmax), typeof(max)}, T) = abs2(zero(T))
281277

282278
mapreduce_empty_iter(f, op, itr, ::HasEltype) = mapreduce_empty(f, op, eltype(itr))
283279
mapreduce_empty_iter(f, op::typeof(&), itr, ::EltypeUnknown) = true
284280
mapreduce_empty_iter(f, op::typeof(|), itr, ::EltypeUnknown) = false
285281
mapreduce_empty_iter(f, op, itr, ::EltypeUnknown) = _empty_reduce_error()
286282

287283
# handling of single-element iterators
284+
"""
285+
Base.reduce_single(f, op, x)
286+
287+
The value to be returned when calling [`reduce`] with `op` over an iterator which contains
288+
a single element `x`.
289+
290+
The default is `x`.
291+
"""
292+
reduce_single(op, x) = x
293+
reduce_single(::typeof(add_tosys), x::SmallSigned) = Int(x)
294+
reduce_single(::typeof(add_tosys), x::SmallUnsigned) = UInt(x)
295+
reduce_single(::typeof(mul_tosys), x::SmallSigned) = Int(x)
296+
reduce_single(::typeof(mul_tosys), x::SmallUnsigned) = UInt(x)
297+
288298
"""
289299
Base.mapreduce_single(f, op, x)
290300
291301
The value to be returned when calling [`mapreduce`] with `f` and `op` over an iterator
292302
which contains a single element `x`.
293303
294-
The default is `f(x)`.
304+
The default is `f(reduce_single(op, x))`.
295305
"""
296-
mapreduce_single(f, op, x) = f(x)
306+
mapreduce_single(f, op, x) = f(reduce_single(op, x))
307+
308+
297309

298310

299311

@@ -325,7 +337,7 @@ end
325337
_mapreduce(f, op, ::IndexCartesian, A::AbstractArray) = mapfoldl(f, op, A)
326338

327339
mapreduce(f, op, A::AbstractArray) = _mapreduce(f, op, IndexStyle(A), A)
328-
mapreduce(f, op, a::Number) = f(a)
340+
mapreduce(f, op, a::Number) = mapreduce_single(f, op, a)
329341

330342
"""
331343
reduce(op, v0, itr)
@@ -403,7 +415,7 @@ In the former case, the integers are widened to system word size and therefore
403415
the result is 128. In the latter case, no such widening happens and integer
404416
overflow results in -128.
405417
"""
406-
sum(f::Callable, a) = mapreduce(promote_sys_size_add f, +, a)
418+
sum(f, a) = mapreduce(f, add_tosys, a)
407419

408420
"""
409421
sum(itr)
@@ -419,7 +431,7 @@ julia> sum(1:20)
419431
210
420432
```
421433
"""
422-
sum(a) = mapreduce(promote_sys_size_add, +, a)
434+
sum(a) = sum(identity, a)
423435
sum(a::AbstractArray{Bool}) = count(a)
424436

425437
## prod
@@ -437,7 +449,7 @@ julia> prod(abs2, [2; 3; 4])
437449
576
438450
```
439451
"""
440-
prod(f::Callable, a) = mapreduce(promote_sys_size_mul f, *, a)
452+
prod(f::Callable, a) = mapreduce(f, mul_tosys, a)
441453

442454
"""
443455
prod(itr)
@@ -453,7 +465,7 @@ julia> prod(1:20)
453465
2432902008176640000
454466
```
455467
"""
456-
prod(a) = mapreduce(promote_sys_size_mul, *, a)
468+
prod(a) = mapreduce(identity, mul_tosys, a)
457469

458470
## maximum & minimum
459471

0 commit comments

Comments
 (0)