Skip to content

Commit

Permalink
max and min of NaN return NaN (closes #7866) (fixes #12552)
Browse files Browse the repository at this point in the history
  • Loading branch information
stevengj committed Aug 11, 2015
1 parent f74f6ee commit 0129abb
Show file tree
Hide file tree
Showing 8 changed files with 41 additions and 38 deletions.
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,8 @@ Library improvements

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

* `max`, `min`, and related functions (`maxmin`, `maximum`, `minimum`, `extrema`) now return `NaN` for `NaN` arguments.

* Random numbers

* Streamlined random number generation APIs [#8246].
Expand Down
11 changes: 5 additions & 6 deletions base/math.jl
Original file line number Diff line number Diff line change
Expand Up @@ -171,18 +171,17 @@ for f in (:atan2, :hypot)
end

max{T<:AbstractFloat}(x::T, y::T) = ifelse((y > x) | (signbit(y) < signbit(x)),
ifelse(isnan(y), x, y), ifelse(isnan(x), y, x))
ifelse(isnan(x), x, y), ifelse(isnan(y), y, x))

@vectorize_2arg Real max

min{T<:AbstractFloat}(x::T, y::T) = ifelse((y < x) | (signbit(y) > signbit(x)),
ifelse(isnan(y), x, y), ifelse(isnan(x), y, x))
ifelse(isnan(x), x, y), ifelse(isnan(y), y, x))
@vectorize_2arg Real min

minmax{T<:AbstractFloat}(x::T, y::T) = ifelse(isnan(x-y), ifelse(isnan(x), (y, y), (x, x)),
ifelse((y < x) | (signbit(y) > signbit(x)), (y, x),
ifelse((y > x) | (signbit(y) < signbit(x)), (x, y),
ifelse(x == x, (x, x), (y, y)))))
minmax{T<:AbstractFloat}(x::T, y::T) =
ifelse(isnan(x) | isnan(y), ifelse(isnan(x), (x,x), (y,y)),
ifelse((y > x) | (signbit(x) > signbit(y)), (x,y), (y,x)))

ldexp(x::Float64,e::Integer) = ccall((:scalbn,libm), Float64, (Float64,Int32), x, Int32(e))
ldexp(x::Float32,e::Integer) = ccall((:scalbnf,libm), Float32, (Float32,Int32), x, Int32(e))
Expand Down
4 changes: 4 additions & 0 deletions base/mpfr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -563,12 +563,16 @@ function log1p(x::BigFloat)
end

function max(x::BigFloat, y::BigFloat)
isnan(x) && return x
isnan(y) && return y
z = BigFloat()
ccall((:mpfr_max, :libmpfr), Int32, (Ptr{BigFloat}, Ptr{BigFloat}, Ptr{BigFloat}, Int32), &z, &x, &y, ROUNDING_MODE[end])
return z
end

function min(x::BigFloat, y::BigFloat)
isnan(x) && return x
isnan(y) && return y
z = BigFloat()
ccall((:mpfr_min, :libmpfr), Int32, (Ptr{BigFloat}, Ptr{BigFloat}, Ptr{BigFloat}, Int32), &z, &x, &y, ROUNDING_MODE[end])
return z
Expand Down
14 changes: 3 additions & 11 deletions base/reduce.jl
Original file line number Diff line number Diff line change
Expand Up @@ -332,19 +332,11 @@ function extrema(itr)
s = start(itr)
done(itr, s) && throw(ArgumentError("collection must be non-empty"))
(v, s) = next(itr, s)
while v != v && !done(itr, s)
(x, s) = next(itr, s)
v = x
end
vmin = v
vmax = v
vmin = vmax = v
while !done(itr, s)
(x, s) = next(itr, s)
if x > vmax
vmax = x
elseif x < vmin
vmin = x
end
vmax = max(x, vmax)
vmin = min(x, vmin)
end
return (vmin, vmax)
end
Expand Down
2 changes: 1 addition & 1 deletion test/math.jl
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,7 @@ end
@test !get_zero_subnormals()

# useful test functions for relative error
err(z, x) = abs(z - x) / abs(x)
err(z, x) = z == x ? 0.0 : abs(z - x) / abs(x)
errc(z, x) = max(err(real(z),real(x)), err(imag(z),imag(x)))

for x in -10.2:0.3456:50
Expand Down
4 changes: 2 additions & 2 deletions test/mpfr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -292,8 +292,8 @@ y = BigFloat(2)
@test max(x,y) == x
@test min(x,y) == y
y = BigFloat(NaN)
@test max(x,y) == x
@test min(x,y) == x
@test isnan(max(x,y))
@test isnan(min(x,y))
@test isnan(max(y,y))
@test isnan(min(y,y))

Expand Down
30 changes: 18 additions & 12 deletions test/numbers.jl
Original file line number Diff line number Diff line change
Expand Up @@ -54,32 +54,38 @@
@test 2.0 * 3.0 == 6.
@test min(1.0,1) == 1

const = isequal # convenient for comparing NaNs

# min, max and minmax
@test minmax(5, 3) == (3, 5)
@test minmax(3., 5.) == (3., 5.)
@test minmax(5., 3.) == (3., 5.)
@test minmax(3., NaN) == (3., 3.)
@test minmax(NaN, 3.) == (3., 3.)
@test isequal(minmax(NaN, NaN), (NaN, NaN))
@test minmax(3., NaN) (NaN, NaN)
@test minmax(NaN, 3) (NaN, NaN)
@test minmax(Inf, NaN) (NaN, NaN)
@test minmax(NaN, Inf) (NaN, NaN)
@test minmax(-Inf, NaN) (NaN, NaN)
@test minmax(NaN, -Inf) (NaN, NaN)
@test minmax(NaN, NaN) (NaN, NaN)
@test min(-0.0,0.0) === min(0.0,-0.0)
@test max(-0.0,0.0) === max(0.0,-0.0)
@test minmax(-0.0,0.0) === minmax(0.0,-0.0)
@test max(-3.2, 5.1) == max(5.1, -3.2) == 5.1
@test min(-3.2, 5.1) == min(5.1, -3.2) == -3.2
@test max(-3.2, Inf) == max(Inf, -3.2) == Inf
@test max(-3.2, NaN) == max(NaN, -3.2) == -3.2
@test max(-3.2, NaN) max(NaN, -3.2) NaN
@test min(5.1, Inf) == min(Inf, 5.1) == 5.1
@test min(5.1, -Inf) == min(-Inf, 5.1) == -Inf
@test min(5.1, NaN) == min(NaN, 5.1) == 5.1
@test min(5.1, -NaN) == min(-NaN, 5.1) == 5.1
@test min(5.1, NaN) min(NaN, 5.1) NaN
@test min(5.1, -NaN) min(-NaN, 5.1) NaN
@test minmax(-3.2, 5.1) == (min(-3.2, 5.1), max(-3.2, 5.1))
@test minmax(-3.2, Inf) == (min(-3.2, Inf), max(-3.2, Inf))
@test minmax(-3.2, NaN) == (min(-3.2, NaN), max(-3.2, NaN))
@test (max(Inf,NaN), max(-Inf,NaN), max(Inf,-NaN), max(-Inf,-NaN)) == (Inf, -Inf, Inf, -Inf)
@test (max(NaN,Inf), max(NaN,-Inf), max(-NaN,Inf), max(-NaN,-Inf)) == (Inf, -Inf, Inf, -Inf)
@test (min(Inf,NaN), min(-Inf,NaN), min(Inf,-NaN), min(-Inf,-NaN)) == (Inf, -Inf, Inf, -Inf)
@test (min(NaN,Inf), min(NaN,-Inf), min(-NaN,Inf), min(-NaN,-Inf)) == (Inf, -Inf, Inf, -Inf)
@test minmax(-Inf,NaN) == (min(-Inf,NaN), max(-Inf,NaN))
@test minmax(-3.2, NaN) (min(-3.2, NaN), max(-3.2, NaN))
@test (max(Inf,NaN), max(-Inf,NaN), max(Inf,-NaN), max(-Inf,-NaN)) (NaN,NaN,NaN,NaN)
@test (max(NaN,Inf), max(NaN,-Inf), max(-NaN,Inf), max(-NaN,-Inf)) (NaN,NaN,NaN,NaN)
@test (min(Inf,NaN), min(-Inf,NaN), min(Inf,-NaN), min(-Inf,-NaN)) (NaN,NaN,NaN,NaN)
@test (min(NaN,Inf), min(NaN,-Inf), min(-NaN,Inf), min(-NaN,-Inf)) (NaN,NaN,NaN,NaN)
@test minmax(-Inf,NaN) (min(-Inf,NaN), max(-Inf,NaN))

# fma
let x = Int64(7)^7
Expand Down
12 changes: 6 additions & 6 deletions test/reduce.jl
Original file line number Diff line number Diff line change
Expand Up @@ -144,13 +144,13 @@ prod2(itr) = invoke(prod, Tuple{Any}, itr)
@test isnan(minimum([NaN]))
@test isequal(extrema([NaN]), (NaN, NaN))

@test maximum([NaN, 2., 3.]) == 3.
@test minimum([NaN, 2., 3.]) == 2.
@test extrema([NaN, 2., 3.]) == (2., 3.)
@test isnan(maximum([NaN, 2., 3.]))
@test isnan(minimum([NaN, 2., 3.]))
@test isequal(extrema([NaN, 2., 3.]), (NaN,NaN))

@test maximum([4., 3., NaN, 5., 2.]) == 5.
@test minimum([4., 3., NaN, 5., 2.]) == 2.
@test extrema([4., 3., NaN, 5., 2.]) == (2., 5.)
@test isnan(maximum([4., 3., NaN, 5., 2.]))
@test isnan(minimum([4., 3., NaN, 5., 2.]))
@test isequal(extrema([4., 3., NaN, 5., 2.]), (NaN,NaN))

@test maxabs(Int[]) == 0
@test_throws ArgumentError Base.minabs(Int[])
Expand Down

0 comments on commit 0129abb

Please sign in to comment.