# Inconsistency between \`findmax\` and \`maximum\` with respect to \`NaN\`

**URL:** https://discourse.julialang.org/t/inconsistency-between-findmax-and-maximum-with-respect-to-nan/4214
**Category:** General Usage
**Created:** [June 12, 2017, 3:16am UTC](https://discourse.julialang.org/t/inconsistency-between-findmax-and-maximum-with-respect-to-nan/4214 "2017-06-12T03:16:00Z")
**Posts on this page:** 10
**Page:** 1

<div class="post-metadata">

### Author: ![wsshin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/wsshin/32/360_2.png) [@wsshin](https://discourse.julialang.org/u/wsshin)
#### Post date: [June 12, 2017, 3:16am UTC](https://discourse.julialang.org/t/inconsistency-between-findmax-and-maximum-with-respect-to-nan/4214/1 "2017-06-12T03:16:00Z")

</div>

I read [this discussion](https://github.com/JuliaLang/julia/pull/12563) about `max` and `maximum` returning `NaN` when the collection includes `NaN`. For example,

```julia
julia> VERSION
v"0.7.0-DEV.82"

julia> v = [1.0, NaN, 2.0]
3-element Array{Float64,1}:
   1.0
 NaN
   2.0

julia> maximum(v)
NaN

```

However, `findmax` still returns the maximum among non-NaN values and its index:

```julia
julia> findmax(v)
(2.0, 3)

```

This seems inconsistent. Is this something intended or a bug?

---

<div class="post-metadata">

### Author: ![bjarthur](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bjarthur/32/9638_2.png) [@bjarthur](https://discourse.julialang.org/u/bjarthur)
#### Post date: [June 12, 2017, 11:12am UTC](https://discourse.julialang.org/t/inconsistency-between-findmax-and-maximum-with-respect-to-nan/4214/2 "2017-06-12T11:12:30Z")

</div>

seems like a bug to me. i’d suggest creating a new issue for it on the julia github repo. or better yet, fix it and submit a PR.

and thanks for the link to the discussion on NaNs. therein i found a reference to [NaNMath.jl](https://github.com/mlubin/NaNMath.jl), which i am going to immediately start using!

---

<div class="post-metadata">

### Author: ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)
#### Post date: [June 12, 2017, 1:34pm UTC](https://discourse.julialang.org/t/inconsistency-between-findmax-and-maximum-with-respect-to-nan/4214/3 "2017-06-12T13:34:47Z")

</div>

This violates certain invariances that users may expect, such as

```julia
findmax(x)[1] == maximum(x)

```

so I would say it is a bug. If we take the “`NaN` should propagate” view, it both should be `NaN`, but I have no good suggestion for the position returned by `findmax` (maybe `0`? yet another corner case). If we take the view that “`NaN` encodes missing data”, both should return `2.0`.

---

<div class="post-metadata">

### Author: ![wsshin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/wsshin/32/360_2.png) [@wsshin](https://discourse.julialang.org/u/wsshin)
#### Post date: [June 12, 2017, 4:42pm UTC](https://discourse.julialang.org/t/inconsistency-between-findmax-and-maximum-with-respect-to-nan/4214/4 "2017-06-12T16:42:36Z")

</div>

Thanks! I just filed an issue: [https://github.com/JuliaLang/julia/issues/22337](https://github.com/JuliaLang/julia/issues/22337).

---

<div class="post-metadata">

### Author: ![wsshin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/wsshin/32/360_2.png) [@wsshin](https://discourse.julialang.org/u/wsshin)
#### Post date: [June 12, 2017, 6:06pm UTC](https://discourse.julialang.org/t/inconsistency-between-findmax-and-maximum-with-respect-to-nan/4214/5 "2017-06-12T18:06:03Z")

</div>

By the way, the original motivation of this question was to find a way to perform `NaN`-ignoring maximum. I thought I could use `findmax` for this if the above reported behavior of `findmax` was intended.

However, now that the above `NaN`-ignoring behavior of `findmax` seems like a bug, I need a better way to find the maximum ignoring `NaN`. Some discussion thread suggested something like `maximum(v[!isnan.(v)])`, which I don’t like because of too many unnecessary allocations.

The best way I’ve figured out is to define `nanmax` that returns the greater of the two numbers ignoring `NaN`, and to use it in `reduce`:

```julia
julia> nanmax(x,y) = isnan(x) ? y : (isnan(y) ? x : max(x,y))
nanmax (generic function with 1 method)

julia> reduce(nanmax, v)
2.0

```

A couple of notes:

- You can generalize this to multidimensional arrays `A` using `reducedim`, as `reducedim(nanmax, A, 2)` that finds the maxima along the second dimension ignoring `NaN`.
- When `A` is `StaticArray`, you can use the type-stable version of this: `reducedim(nanmax, A, Val{2})`. By using `Val{2}` instead of `2` as the search dimension indicator, you can make `reducedim` to produce a `StaticArray`. See [https://github.com/JuliaArrays/StaticArrays.jl/pull/86](https://github.com/JuliaArrays/StaticArrays.jl/pull/86).

Edit: @DNF pointed out that `y > x` returns `false` for all `x` if `y = NaN`, so the above `nanmax` can be simplified to this:

```julia
nanmax(x, y) = isnan(x) ? y : (y > x ? y : x)

```

---

<div class="post-metadata">

### Author: ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)
#### Post date: [June 14, 2017, 8:25am UTC](https://discourse.julialang.org/t/inconsistency-between-findmax-and-maximum-with-respect-to-nan/4214/6 "2017-06-14T08:25:45Z")

</div>

For the array maximum you can save quite a bit of time by only checking for `isnan` up to the point where the first non-`NaN` element is encountered, and then switching to ordinary `>` comparison, since `NaN > maxval` is `false`.

The code isn’t as clean though.

---

<div class="post-metadata">

### Author: ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)
#### Post date: [June 14, 2017, 8:43am UTC](https://discourse.julialang.org/t/inconsistency-between-findmax-and-maximum-with-respect-to-nan/4214/7 "2017-06-14T08:43:25Z")

</div>

Also, I think

```julia
nanmax(x, y) = isnan(x) ? y : (y > x ? y : x)

```

is slightly faster, and has shorter generated code.

---

<div class="post-metadata">

### Author: ![wsshin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/wsshin/32/360_2.png) [@wsshin](https://discourse.julialang.org/u/wsshin)
#### Post date: [June 14, 2017, 7:29pm UTC](https://discourse.julialang.org/t/inconsistency-between-findmax-and-maximum-with-respect-to-nan/4214/8 "2017-06-14T19:29:13Z")

</div>

> [@DNF](#):
>
> For the array maximum you can save quite a bit of time by only checking for isnan up to the point where the first non-NaN element is encountered, and then switching to ordinary \> comparison, since NaN \> maxval is false.
> 
> The code isn’t as clean though.

How about this? Define `nanmax` as

```julia
nanmax(x, y) = x<y ? y : x

```

and do

```julia
reduce(nanmax, -Inf, v)

```

The above `nanmax` does not perform `isnan` at all, so it’s a bit weird to call it `nanmax`, but it works by the following reason.

If `x` is guaranteed to be non-`NaN`, the above `nanmax` always returns the correct non-`NaN` maximum between `x` and `y`, regardless of `y` being `NaN` or non-`NaN`. Now, note that `reduce(nanmax, v)` performs reduction by putting the intermediate reduction result up to the current entry of `v` into `x` and the next entry of `v` into `y`. Therefore, if the first entry of `v` is non-`NaN`, `x` of `nanmax(x,y)` stays always non-`NaN` throughout the entire reduction procedure of `reduce(nanmax, v)`.

The only case `reduce(nanmax, v)` does not work is when the first entry of `v` is `NaN`. We can avoid this case by using `reduce(nanmax, -Inf, v)`, which is effectively the same as `reduce(nanmax, w)` for `w = [-Inf; v]` whose first entry is non-`NaN`.

The problem of this is that it produces `-Inf` even if `v` is completely filled with `NaN`, for which case we may want to get `NaN`. However, if we know `v` has at least one non-`NaN` entry, this technique works.

Inspired by this idea, we can define `nanmaximum` more generally as follows:

```julia
nanmaximum(v::AbstractVector{T}) where {T<:Number} = reduce((x,y) -> x<y ? y : x, typemin(T), v)

```

---

<div class="post-metadata">

### Author: ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)
#### Post date: [June 14, 2017, 7:43pm UTC](https://discourse.julialang.org/t/inconsistency-between-findmax-and-maximum-with-respect-to-nan/4214/10 "2017-06-14T19:43:55Z")

</div>

Yes, this is pretty much what I was thinking as well. Here’s my (ugly) code which also handles all `NaN`s. Speed is the same as your code:

```julia
function _maximum(y, istart)
    val = typemin(eltype(y))
    for i in eachindex(y)[istart:end]
        if y[i] > val
            val = y[i]
        end
    end
    return val
end

function nanmaximum(y)
    for i in eachindex(y)
        if !isnan(y[i])
            return _maximum(y, i)
        end
    end
    return convert(eltype(y), NaN)
end

```

---

<div class="post-metadata">

### Author: ![mkborregaard](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkborregaard/32/556_2.png) [@mkborregaard](https://discourse.julialang.org/u/mkborregaard)
#### Post date: [June 15, 2017, 9:41am UTC](https://discourse.julialang.org/t/inconsistency-between-findmax-and-maximum-with-respect-to-nan/4214/11 "2017-06-15T09:41:42Z")

</div>

@bjarthur above linked to NaNMath.jl, which I believe is the intended way of dealing with this, i.e. you could use `NaNMath.maximum` rather than implementing your own replacemen… The code for `maximum` in NaNMath looks a lot like @DNF’s

```julia
function maximum{T<:AbstractFloat}(x::AbstractArray{T})
    result = convert(eltype(x), NaN)
    for i in x
        if !isnan(i)
            if (isnan(result) || i > result)
                result = i
            end
        end
    end
    return result
end

```

Note that this (and DNF’s code) may not work for all iterable collection of all eltypes, which is why NaNMath restricts it to `{T<:AbstractFloat}(x::AbstractArray{T})`. This can be annoying in practice if your code sometimes passes something else, like a `UnitRange{Int}` to the function.  
In Plots this was resolved by defining an internal function that dispatched to the NaNMath versoin for `{T<:AbstractFloat}(x::AbstractArray{T})`, and to the Base version as fallback.
