Skip to content

Commit 1cffc82

Browse files
committed
max and min of NaN return NaN (closes JuliaLang#7866) (fixes #12552)
1 parent 1774871 commit 1cffc82

File tree

8 files changed

+47
-37
lines changed

8 files changed

+47
-37
lines changed

NEWS.md

+2
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,8 @@ Library improvements
334334

335335
* The function `primesmask` which generates a prime sieve for a user defined closed interval is now exported ([#12025]).
336336

337+
* `max`, `min`, and related functions (`maxmin`, `maximum`, `minimum`, `extrema`) now return `NaN` for `NaN` arguments.
338+
337339
* Random numbers
338340

339341
* Streamlined random number generation APIs [#8246].

base/math.jl

+5-6
Original file line numberDiff line numberDiff line change
@@ -171,18 +171,17 @@ for f in (:atan2, :hypot)
171171
end
172172

173173
max{T<:AbstractFloat}(x::T, y::T) = ifelse((y > x) | (signbit(y) < signbit(x)),
174-
ifelse(isnan(y), x, y), ifelse(isnan(x), y, x))
174+
ifelse(isnan(x), x, y), ifelse(isnan(y), y, x))
175175

176176
@vectorize_2arg Real max
177177

178178
min{T<:AbstractFloat}(x::T, y::T) = ifelse((y < x) | (signbit(y) > signbit(x)),
179-
ifelse(isnan(y), x, y), ifelse(isnan(x), y, x))
179+
ifelse(isnan(x), x, y), ifelse(isnan(y), y, x))
180180
@vectorize_2arg Real min
181181

182-
minmax{T<:AbstractFloat}(x::T, y::T) = ifelse(isnan(x-y), ifelse(isnan(x), (y, y), (x, x)),
183-
ifelse((y < x) | (signbit(y) > signbit(x)), (y, x),
184-
ifelse((y > x) | (signbit(y) < signbit(x)), (x, y),
185-
ifelse(x == x, (x, x), (y, y)))))
182+
minmax{T<:AbstractFloat}(x::T, y::T) =
183+
ifelse(isnan(x) | isnan(y), ifelse(isnan(x), (x,x), (y,y)),
184+
ifelse((y > x) | (signbit(x) > signbit(y)), (x,y), (y,x)))
186185

187186
ldexp(x::Float64,e::Integer) = ccall((:scalbn,libm), Float64, (Float64,Int32), x, Int32(e))
188187
ldexp(x::Float32,e::Integer) = ccall((:scalbnf,libm), Float32, (Float32,Int32), x, Int32(e))

base/mpfr.jl

+4
Original file line numberDiff line numberDiff line change
@@ -562,12 +562,16 @@ function log1p(x::BigFloat)
562562
end
563563

564564
function max(x::BigFloat, y::BigFloat)
565+
isnan(x) && return x
566+
isnan(y) && return y
565567
z = BigFloat()
566568
ccall((:mpfr_max, :libmpfr), Int32, (Ptr{BigFloat}, Ptr{BigFloat}, Ptr{BigFloat}, Int32), &z, &x, &y, ROUNDING_MODE[end])
567569
return z
568570
end
569571

570572
function min(x::BigFloat, y::BigFloat)
573+
isnan(x) && return x
574+
isnan(y) && return y
571575
z = BigFloat()
572576
ccall((:mpfr_min, :libmpfr), Int32, (Ptr{BigFloat}, Ptr{BigFloat}, Ptr{BigFloat}, Int32), &z, &x, &y, ROUNDING_MODE[end])
573577
return z

base/reduce.jl

+3-11
Original file line numberDiff line numberDiff line change
@@ -332,19 +332,11 @@ function extrema(itr)
332332
s = start(itr)
333333
done(itr, s) && throw(ArgumentError("collection must be non-empty"))
334334
(v, s) = next(itr, s)
335-
while v != v && !done(itr, s)
336-
(x, s) = next(itr, s)
337-
v = x
338-
end
339-
vmin = v
340-
vmax = v
335+
vmin = vmax = v
341336
while !done(itr, s)
342337
(x, s) = next(itr, s)
343-
if x > vmax
344-
vmax = x
345-
elseif x < vmin
346-
vmin = x
347-
end
338+
vmax = max(x, vmax)
339+
vmin = min(x, vmin)
348340
end
349341
return (vmin, vmax)
350342
end

test/linalg/dense.jl

+7
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,13 @@ for elty in (Float32, Float64, BigFloat, Complex{Float32}, Complex{Float64}, Com
127127
@test_approx_eq norm(xs, 3) cbrt(5)
128128
@test_approx_eq norm(xs, Inf) 1
129129

130+
# Issue #12552:
131+
if real(elty) <: AbstractFloat
132+
for p in [-Inf,-1,1,2,3,Inf]
133+
@test isnan(norm(elty[0,NaN],p))
134+
end
135+
end
136+
130137
## Number
131138
norm(x[1:1]) === norm(x[1], -Inf)
132139
norm(x[1:1]) === norm(x[1], 0)

test/mpfr.jl

+2-2
Original file line numberDiff line numberDiff line change
@@ -292,8 +292,8 @@ y = BigFloat(2)
292292
@test max(x,y) == x
293293
@test min(x,y) == y
294294
y = BigFloat(NaN)
295-
@test max(x,y) == x
296-
@test min(x,y) == x
295+
@test isnan(max(x,y))
296+
@test isnan(min(x,y))
297297
@test isnan(max(y,y))
298298
@test isnan(min(y,y))
299299

test/numbers.jl

+18-12
Original file line numberDiff line numberDiff line change
@@ -54,32 +54,38 @@
5454
@test 2.0 * 3.0 == 6.
5555
@test min(1.0,1) == 1
5656

57+
const = isequal # convenient for comparing NaNs
58+
5759
# min, max and minmax
5860
@test minmax(5, 3) == (3, 5)
5961
@test minmax(3., 5.) == (3., 5.)
6062
@test minmax(5., 3.) == (3., 5.)
61-
@test minmax(3., NaN) == (3., 3.)
62-
@test minmax(NaN, 3.) == (3., 3.)
63-
@test isequal(minmax(NaN, NaN), (NaN, NaN))
63+
@test minmax(3., NaN) (NaN, NaN)
64+
@test minmax(NaN, 3) (NaN, NaN)
65+
@test minmax(Inf, NaN) (NaN, NaN)
66+
@test minmax(NaN, Inf) (NaN, NaN)
67+
@test minmax(-Inf, NaN) (NaN, NaN)
68+
@test minmax(NaN, -Inf) (NaN, NaN)
69+
@test minmax(NaN, NaN) (NaN, NaN)
6470
@test min(-0.0,0.0) === min(0.0,-0.0)
6571
@test max(-0.0,0.0) === max(0.0,-0.0)
6672
@test minmax(-0.0,0.0) === minmax(0.0,-0.0)
6773
@test max(-3.2, 5.1) == max(5.1, -3.2) == 5.1
6874
@test min(-3.2, 5.1) == min(5.1, -3.2) == -3.2
6975
@test max(-3.2, Inf) == max(Inf, -3.2) == Inf
70-
@test max(-3.2, NaN) == max(NaN, -3.2) == -3.2
76+
@test max(-3.2, NaN) max(NaN, -3.2) NaN
7177
@test min(5.1, Inf) == min(Inf, 5.1) == 5.1
7278
@test min(5.1, -Inf) == min(-Inf, 5.1) == -Inf
73-
@test min(5.1, NaN) == min(NaN, 5.1) == 5.1
74-
@test min(5.1, -NaN) == min(-NaN, 5.1) == 5.1
79+
@test min(5.1, NaN) min(NaN, 5.1) NaN
80+
@test min(5.1, -NaN) min(-NaN, 5.1) NaN
7581
@test minmax(-3.2, 5.1) == (min(-3.2, 5.1), max(-3.2, 5.1))
7682
@test minmax(-3.2, Inf) == (min(-3.2, Inf), max(-3.2, Inf))
77-
@test minmax(-3.2, NaN) == (min(-3.2, NaN), max(-3.2, NaN))
78-
@test (max(Inf,NaN), max(-Inf,NaN), max(Inf,-NaN), max(-Inf,-NaN)) == (Inf, -Inf, Inf, -Inf)
79-
@test (max(NaN,Inf), max(NaN,-Inf), max(-NaN,Inf), max(-NaN,-Inf)) == (Inf, -Inf, Inf, -Inf)
80-
@test (min(Inf,NaN), min(-Inf,NaN), min(Inf,-NaN), min(-Inf,-NaN)) == (Inf, -Inf, Inf, -Inf)
81-
@test (min(NaN,Inf), min(NaN,-Inf), min(-NaN,Inf), min(-NaN,-Inf)) == (Inf, -Inf, Inf, -Inf)
82-
@test minmax(-Inf,NaN) == (min(-Inf,NaN), max(-Inf,NaN))
83+
@test minmax(-3.2, NaN) (min(-3.2, NaN), max(-3.2, NaN))
84+
@test (max(Inf,NaN), max(-Inf,NaN), max(Inf,-NaN), max(-Inf,-NaN)) (NaN,NaN,NaN,NaN)
85+
@test (max(NaN,Inf), max(NaN,-Inf), max(-NaN,Inf), max(-NaN,-Inf)) (NaN,NaN,NaN,NaN)
86+
@test (min(Inf,NaN), min(-Inf,NaN), min(Inf,-NaN), min(-Inf,-NaN)) (NaN,NaN,NaN,NaN)
87+
@test (min(NaN,Inf), min(NaN,-Inf), min(-NaN,Inf), min(-NaN,-Inf)) (NaN,NaN,NaN,NaN)
88+
@test minmax(-Inf,NaN) (min(-Inf,NaN), max(-Inf,NaN))
8389

8490
# fma
8591
let x = Int64(7)^7

test/reduce.jl

+6-6
Original file line numberDiff line numberDiff line change
@@ -144,13 +144,13 @@ prod2(itr) = invoke(prod, Tuple{Any}, itr)
144144
@test isnan(minimum([NaN]))
145145
@test isequal(extrema([NaN]), (NaN, NaN))
146146

147-
@test maximum([NaN, 2., 3.]) == 3.
148-
@test minimum([NaN, 2., 3.]) == 2.
149-
@test extrema([NaN, 2., 3.]) == (2., 3.)
147+
@test isnan(maximum([NaN, 2., 3.]))
148+
@test isnan(minimum([NaN, 2., 3.]))
149+
@test isequal(extrema([NaN, 2., 3.]), (NaN,NaN))
150150

151-
@test maximum([4., 3., NaN, 5., 2.]) == 5.
152-
@test minimum([4., 3., NaN, 5., 2.]) == 2.
153-
@test extrema([4., 3., NaN, 5., 2.]) == (2., 5.)
151+
@test isnan(maximum([4., 3., NaN, 5., 2.]))
152+
@test isnan(minimum([4., 3., NaN, 5., 2.]))
153+
@test isequal(extrema([4., 3., NaN, 5., 2.]), (NaN,NaN))
154154

155155
@test maxabs(Int[]) == 0
156156
@test_throws ArgumentError Base.minabs(Int[])

0 commit comments

Comments
 (0)