5
5
# ##### Generic (map)reduce functions ######
6
6
7
7
if Int === Int32
8
- const SmallSigned = Union{Int8,Int16}
9
- const SmallUnsigned = Union{UInt8,UInt16}
8
+ const SmallSigned = Union{Int8,Int16}
9
+ const SmallUnsigned = Union{UInt8,UInt16}
10
10
else
11
- const SmallSigned = Union{Int8,Int16,Int32}
12
- const SmallUnsigned = Union{UInt8,UInt16,UInt32}
11
+ const SmallSigned = Union{Int8,Int16,Int32}
12
+ const SmallUnsigned = Union{UInt8,UInt16,UInt32}
13
13
end
14
14
15
- const CommonReduceResult = Union{UInt64,UInt128,Int64,Int128,Float16,Float32,Float64}
16
- const WidenReduceResult = Union{SmallSigned, SmallUnsigned}
17
-
18
- promote_sys_size {T} (:: Type{T} ) = T
19
- promote_sys_size {T<:SmallSigned} (:: Type{T} ) = Int
20
- promote_sys_size {T<:SmallUnsigned} (:: Type{T} ) = UInt
21
- # r_promote_type: promote T to the type of reduce(op, ::Array{T})
22
- # (some "extra" methods are required here to avoid ambiguity warnings)
23
- r_promote_type (op, :: Type{T} ) where {T} = T
24
- r_promote_type (op, :: Type{T} ) where {T<: WidenReduceResult } = promote_sys_size (T)
25
- r_promote_type (:: typeof (+ ), :: Type{T} ) where {T<: WidenReduceResult } = promote_sys_size (T)
26
- r_promote_type (:: typeof (* ), :: Type{T} ) where {T<: WidenReduceResult } = promote_sys_size (T)
27
- r_promote_type (:: typeof (+ ), :: Type{T} ) where {T<: Number } = typeof (zero (T)+ zero (T))
28
- r_promote_type (:: typeof (* ), :: Type{T} ) where {T<: Number } = typeof (one (T)* one (T))
29
- r_promote_type (:: typeof (scalarmax), :: Type{T} ) where {T<: WidenReduceResult } = T
30
- r_promote_type (:: typeof (scalarmin), :: Type{T} ) where {T<: WidenReduceResult } = T
31
- r_promote_type (:: typeof (max), :: Type{T} ) where {T<: WidenReduceResult } = T
32
- r_promote_type (:: typeof (min), :: Type{T} ) where {T<: WidenReduceResult } = T
33
-
34
- # r_promote: promote x to the type of reduce(op, [x])
35
- r_promote (op, x:: T ) where {T} = convert (r_promote_type (op, T), x)
15
+ # Certain reductions like sum and prod may wish to promote the items being
16
+ # reduced over to an appropriate size.
17
+ promote_sys_size (x) = x
18
+ promote_sys_size (x:: SmallSigned ) = Int (x)
19
+ promote_sys_size (x:: SmallUnsigned ) = UInt (x)
36
20
37
21
# # foldl && mapfoldl
38
22
39
23
@noinline function mapfoldl_impl (f, op, v0, itr, i)
40
24
# Unroll the while loop once; if v0 is known, the call to op may
41
25
# be evaluated at compile time
42
26
if done (itr, i)
43
- return r_promote (op, v0)
27
+ return v0
44
28
else
45
29
(x, i) = next (itr, i)
46
- v = op (r_promote (op, v0) , f (x))
30
+ v = op (v0 , f (x))
47
31
while ! done (itr, i)
48
32
@inbounds (x, i) = next (itr, i)
49
33
v = op (v, f (x))
@@ -69,7 +53,7 @@ this cannot be used with empty collections (see `reduce(op, itr)`).
69
53
function mapfoldl (f, op, itr)
70
54
i = start (itr)
71
55
if done (itr, i)
72
- return Base. mr_empty_iter (f, op, itr, iteratoreltype (itr))
56
+ return Base. mapreduce_empty_iter (f, op, itr, iteratoreltype (itr))
73
57
end
74
58
(x, i) = next (itr, i)
75
59
v0 = f (x)
@@ -108,10 +92,10 @@ function mapfoldr_impl(f, op, v0, itr, i::Integer)
108
92
# Unroll the while loop once; if v0 is known, the call to op may
109
93
# be evaluated at compile time
110
94
if isempty (itr) || i == 0
111
- return r_promote (op, v0)
95
+ return v0
112
96
else
113
97
x = itr[i]
114
- v = op (f (x), r_promote (op, v0) )
98
+ v = op (f (x), v0 )
115
99
while i > 1
116
100
x = itr[i -= 1 ]
117
101
v = op (f (x), v)
@@ -137,7 +121,7 @@ this cannot be used with empty collections (see `reduce(op, itr)`).
137
121
function mapfoldr (f, op, itr)
138
122
i = endof (itr)
139
123
if isempty (itr)
140
- return Base. mr_empty_iter (f, op, itr, iteratoreltype (itr))
124
+ return Base. mapreduce_empty_iter (f, op, itr, iteratoreltype (itr))
141
125
end
142
126
return mapfoldr_impl (f, op, f (itr[i]), itr, i- 1 )
143
127
end
@@ -180,12 +164,12 @@ foldr(op, itr) = mapfoldr(identity, op, itr)
180
164
@noinline function mapreduce_impl (f, op, A:: AbstractArray , ifirst:: Integer , ilast:: Integer , blksize:: Int )
181
165
if ifirst == ilast
182
166
@inbounds a1 = A[ifirst]
183
- return r_promote (op, f (a1) )
167
+ return f (a1)
184
168
elseif ifirst + blksize > ilast
185
169
# sequential portion
186
170
@inbounds a1 = A[ifirst]
187
171
@inbounds a2 = A[ifirst+ 1 ]
188
- v = op (r_promote (op, f (a1)), r_promote (op, f (a2) ))
172
+ v = op (f (a1), f (a2))
189
173
@simd for i = ifirst + 2 : ilast
190
174
@inbounds ai = A[i]
191
175
v = op (v, f (ai))
@@ -244,39 +228,49 @@ pairwise_blocksize(::typeof(abs2), ::typeof(+)) = 4096
244
228
245
229
# handling empty arrays
246
230
_empty_reduce_error () = throw (ArgumentError (" reducing over an empty collection is not allowed" ))
247
- mr_empty (f, op, T) = _empty_reduce_error ()
248
- # use zero(T)::T to improve type information when zero(T) is not defined
249
- mr_empty (:: typeof (identity), op:: typeof (+ ), T) = r_promote (op, zero (T):: T )
250
- mr_empty (:: typeof (abs), op:: typeof (+ ), T) = r_promote (op, abs (zero (T):: T ))
251
- mr_empty (:: typeof (abs2), op:: typeof (+ ), T) = r_promote (op, abs2 (zero (T):: T ))
252
- mr_empty (:: typeof (identity), op:: typeof (* ), T) = r_promote (op, one (T):: T )
253
- mr_empty (:: typeof (abs), op:: typeof (scalarmax), T) = abs (zero (T):: T )
254
- mr_empty (:: typeof (abs2), op:: typeof (scalarmax), T) = abs2 (zero (T):: T )
255
- mr_empty (:: typeof (abs), op:: typeof (max), T) = mr_empty (abs, scalarmax, T)
256
- mr_empty (:: typeof (abs2), op:: typeof (max), T) = mr_empty (abs2, scalarmax, T)
257
- mr_empty (f, op:: typeof (& ), T) = true
258
- mr_empty (f, op:: typeof (| ), T) = false
259
-
260
- mr_empty_iter (f, op, itr, :: HasEltype ) = mr_empty (f, op, eltype (itr))
261
- mr_empty_iter (f, op:: typeof (& ), itr, :: EltypeUnknown ) = true
262
- mr_empty_iter (f, op:: typeof (| ), itr, :: EltypeUnknown ) = false
263
- mr_empty_iter (f, op, itr, :: EltypeUnknown ) = _empty_reduce_error ()
231
+ reduce_empty (op, T) = _empty_reduce_error ()
232
+ reduce_empty (:: typeof (+ ), T) = zero (T)
233
+ reduce_empty (:: typeof (* ), T) = one (T)
234
+ reduce_empty (:: typeof (& ), :: Type{Bool} ) = true
235
+ reduce_empty (:: typeof (| ), :: Type{Bool} ) = false
236
+
237
+ mapreduce_empty (f, op, T) = _empty_reduce_error ()
238
+ mapreduce_empty (:: typeof (identity), op, T) = reduce_empty (op, T)
239
+ mapreduce_empty (:: typeof (promote_sys_size), op, T) =
240
+ promote_sys_size (mapreduce_empty (identity, op, T))
241
+ mapreduce_empty (:: typeof (abs), :: typeof (+ ), T) = abs (zero (T))
242
+ mapreduce_empty (:: typeof (abs2), :: typeof (+ ), T) = abs2 (zero (T))
243
+ mapreduce_empty (:: typeof (abs), :: Union{typeof(scalarmax), typeof(max)} , T) =
244
+ abs (zero (T))
245
+ mapreduce_empty (:: typeof (abs2), :: Union{typeof(scalarmax), typeof(max)} , T) =
246
+ abs2 (zero (T))
247
+
248
+ # Allow mapreduce_empty to “see through” promote_sys_size
249
+ let ComposedFunction = typename (typeof (identity ∘ identity)). wrapper
250
+ global mapreduce_empty (f:: ComposedFunction{typeof(promote_sys_size)} , op, T) =
251
+ promote_sys_size (mapreduce_empty (f. g, op, T))
252
+ end
253
+
254
+ mapreduce_empty_iter (f, op, itr, :: HasEltype ) = mapreduce_empty (f, op, eltype (itr))
255
+ mapreduce_empty_iter (f, op:: typeof (& ), itr, :: EltypeUnknown ) = true
256
+ mapreduce_empty_iter (f, op:: typeof (| ), itr, :: EltypeUnknown ) = false
257
+ mapreduce_empty_iter (f, op, itr, :: EltypeUnknown ) = _empty_reduce_error ()
264
258
265
259
_mapreduce (f, op, A:: AbstractArray ) = _mapreduce (f, op, IndexStyle (A), A)
266
260
267
261
function _mapreduce (f, op, :: IndexLinear , A:: AbstractArray{T} ) where T
268
262
inds = linearindices (A)
269
263
n = length (inds)
270
264
if n == 0
271
- return mr_empty (f, op, T)
265
+ return mapreduce_empty (f, op, T)
272
266
elseif n == 1
273
267
@inbounds a1 = A[inds[1 ]]
274
- return r_promote (op, f (a1) )
268
+ return f (a1)
275
269
elseif n < 16 # process short array here, avoid mapreduce_impl() compilation
276
270
@inbounds i = inds[1 ]
277
271
@inbounds a1 = A[i]
278
272
@inbounds a2 = A[i+= 1 ]
279
- s = op (r_promote (op, f (a1)), r_promote (op, f (a2) ))
273
+ s = op (f (a1), f (a2))
280
274
while i < last (inds)
281
275
@inbounds Ai = A[i+= 1 ]
282
276
s = op (s, f (Ai))
@@ -299,9 +293,6 @@ Reduce the given collection `itr` with the given binary operator `op`. `v0` must
299
293
neutral element for `op` that will be returned for empty collections. It is unspecified
300
294
whether `v0` is used for non-empty collections.
301
295
302
- The return type is `Int` (`UInt`) for (un)signed integers of less than system word size.
303
- For all other arguments, a common return type is found to which all arguments are promoted.
304
-
305
296
Reductions for certain commonly-used operators may have special implementations, and
306
297
should be used instead: `maximum(itr)`, `minimum(itr)`, `sum(itr)`, `prod(itr)`,
307
298
`any(itr)`, `all(itr)`.
@@ -347,24 +338,47 @@ reduce(op, a::Number) = a
347
338
348
339
Sum the results of calling function `f` on each element of `itr`.
349
340
341
+ The return type is `Int` for signed integers of less than system word size, and
342
+ `UInt` for unsigned integers of less than system word size. For all other
343
+ arguments, a common return type is found to which all arguments are promoted.
344
+
350
345
```jldoctest
351
346
julia> sum(abs2, [2; 3; 4])
352
347
29
353
348
```
349
+
350
+ Note the important difference between `sum(A)` and `reduce(+, A)` for arrays
351
+ with small integer eltype:
352
+
353
+ ```jldoctest
354
+ julia> sum(Int8[100, 28])
355
+ 128
356
+
357
+ julia> reduce(+, Int8[100, 28])
358
+ -128
359
+ ```
360
+
361
+ In the former case, the integers are widened to system word size and therefore
362
+ the result is 128. In the latter case, no such widening happens and integer
363
+ overflow results in -128.
354
364
"""
355
- sum (f:: Callable , a) = mapreduce (f, + , a)
365
+ sum (f:: Callable , a) = mapreduce (promote_sys_size ∘ f, + , a)
356
366
357
367
"""
358
368
sum(itr)
359
369
360
370
Returns the sum of all elements in a collection.
361
371
372
+ The return type is `Int` for signed integers of less than system word size, and
373
+ `UInt` for unsigned integers of less than system word size. For all other
374
+ arguments, a common return type is found to which all arguments are promoted.
375
+
362
376
```jldoctest
363
377
julia> sum(1:20)
364
378
210
365
379
```
366
380
"""
367
- sum (a) = mapreduce (identity , + , a)
381
+ sum (a) = mapreduce (promote_sys_size , + , a)
368
382
sum (a:: AbstractArray{Bool} ) = count (a)
369
383
370
384
@@ -379,7 +393,7 @@ summation algorithm for additional accuracy.
379
393
"""
380
394
function sum_kbn (A)
381
395
T = _default_eltype (typeof (A))
382
- c = r_promote ( + , zero (T):: T )
396
+ c = promote_sys_size ( zero (T):: T )
383
397
i = start (A)
384
398
if done (A, i)
385
399
return c
@@ -405,24 +419,32 @@ end
405
419
406
420
Returns the product of `f` applied to each element of `itr`.
407
421
422
+ The return type is `Int` for signed integers of less than system word size, and
423
+ `UInt` for unsigned integers of less than system word size. For all other
424
+ arguments, a common return type is found to which all arguments are promoted.
425
+
408
426
```jldoctest
409
427
julia> prod(abs2, [2; 3; 4])
410
428
576
411
429
```
412
430
"""
413
- prod (f:: Callable , a) = mapreduce (f, * , a)
431
+ prod (f:: Callable , a) = mapreduce (promote_sys_size ∘ f, * , a)
414
432
415
433
"""
416
434
prod(itr)
417
435
418
436
Returns the product of all elements of a collection.
419
437
438
+ The return type is `Int` for signed integers of less than system word size, and
439
+ `UInt` for unsigned integers of less than system word size. For all other
440
+ arguments, a common return type is found to which all arguments are promoted.
441
+
420
442
```jldoctest
421
443
julia> prod(1:20)
422
444
2432902008176640000
423
445
```
424
446
"""
425
- prod (a) = mapreduce (identity , * , a)
447
+ prod (a) = mapreduce (promote_sys_size , * , a)
426
448
427
449
# # maximum & minimum
428
450
0 commit comments