Skip to content

Commit ad7f3c3

Browse files
authored
Merge pull request #14 from ararslan/aa/min-max
Add IEEE 754-2008 compliant min and max
2 parents 6da4a4e + 1d68647 commit ad7f3c3

File tree

3 files changed

+93
-0
lines changed

3 files changed

+93
-0
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ minimum
1919
mean
2020
var
2121
std
22+
min
23+
max
2224
```
2325

2426
Example:

src/NaNMath.jl

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,4 +211,73 @@ function std{T<:AbstractFloat}(x::Vector{T})
211211
return sqrt(var(x))
212212
end
213213

214+
"""
215+
NaNMath.min(x, y)
216+
217+
Compute the IEEE 754-2008 compliant minimum of `x` and `y`. As of version 0.6 of Julia,
218+
`Base.min(x, y)` will return `NaN` if `x` or `y` is `NaN`. `NanMath.min` favors values over
219+
`NaN`, and will return whichever `x` or `y` is not `NaN` in that case.
220+
221+
## Examples
222+
223+
```julia
224+
julia> NanMath.min(NaN, 0.0)
225+
0.0
226+
227+
julia> NaNMath.min(1, 2)
228+
1
229+
```
230+
"""
231+
min{T<:AbstractFloat}(x::T, y::T) = ifelse((y < x) | (signbit(y) > signbit(x)),
232+
ifelse(isnan(y), x, y),
233+
ifelse(isnan(x), y, x))
234+
235+
"""
236+
NaNMath.max(x, y)
237+
238+
Compute the IEEE 754-2008 compliant maximum of `x` and `y`. As of version 0.6 of Julia,
239+
`Base.max(x, y)` will return `NaN` if `x` or `y` is `NaN`. `NaNMath.max` favors values over
240+
`NaN`, and will return whichever `x` or `y` is not `NaN` in that case.
241+
242+
## Examples
243+
244+
```julia
245+
julia> NaNMath.max(NaN, 0.0)
246+
0.0
247+
248+
julia> NaNMath.max(1, 2)
249+
2
250+
```
251+
"""
252+
max{T<:AbstractFloat}(x::T, y::T) = ifelse((y > x) | (signbit(y) < signbit(x)),
253+
ifelse(isnan(y), x, y),
254+
ifelse(isnan(x), y, x))
255+
256+
min(x::Real, y::Real) = min(promote(x, y)...)
257+
max(x::Real, y::Real) = max(promote(x, y)...)
258+
259+
function min(x::BigFloat, y::BigFloat)
260+
isnan(x) && return y
261+
isnan(y) && return x
262+
return Base.min(x, y)
263+
end
264+
265+
function max(x::BigFloat, y::BigFloat)
266+
isnan(x) && return y
267+
isnan(y) && return x
268+
return Base.max(x, y)
269+
end
270+
271+
# Integers can't represent NaN
272+
min(x::Integer, y::Integer) = Base.min(x, y)
273+
max(x::Integer, y::Integer) = Base.max(x, y)
274+
275+
min(x::Real) = x
276+
max(x::Real) = x
277+
278+
# Multi-arg versions
279+
for f in (:min, :max)
280+
@eval ($f)(a, b, c, xs...) = Base.afoldl($f, ($f)(($f)(a, b), c), xs...)
281+
end
282+
214283
end

test/runtests.jl

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,25 @@ using Base.Test
1515
@test NaNMath.mean([1., 2., NaN]) == 1.5
1616
@test NaNMath.var([1., 2., NaN]) == 0.5
1717
@test NaNMath.std([1., 2., NaN]) == 0.7071067811865476
18+
19+
@test NaNMath.min(1, 2) == 1
20+
@test NaNMath.min(1.0, 2.0) == 1.0
21+
@test NaNMath.min(1, 2.0) == 1.0
22+
@test NaNMath.min(BigFloat(1.0), 2.0) == BigFloat(1.0)
23+
@test NaNMath.min(BigFloat(1.0), BigFloat(2.0)) == BigFloat(1.0)
24+
@test NaNMath.min(NaN, 1) == 1.0
25+
@test NaNMath.min(NaN32, 1) == 1.0f0
26+
@test isnan(NaNMath.min(NaN, NaN))
27+
@test isnan(NaNMath.min(NaN))
28+
@test NaNMath.min(NaN, NaN, 0.0, 1.0) == 0.0
29+
30+
@test NaNMath.max(1, 2) == 2
31+
@test NaNMath.max(1.0, 2.0) == 2.0
32+
@test NaNMath.max(1, 2.0) == 2.0
33+
@test NaNMath.max(BigFloat(1.0), 2.0) == BigFloat(2.0)
34+
@test NaNMath.max(BigFloat(1.0), BigFloat(2.0)) == BigFloat(2.0)
35+
@test NaNMath.max(NaN, 1) == 1.0
36+
@test NaNMath.max(NaN32, 1) == 1.0f0
37+
@test isnan(NaNMath.max(NaN, NaN))
38+
@test isnan(NaNMath.max(NaN))
39+
@test NaNMath.max(NaN, NaN, 0.0, 1.0) == 1.0

0 commit comments

Comments
 (0)