
On Fri, Jul 3, 2020 at 5:07 PM Steven D'Aprano <steve@pearwood.info> wrote:
As I recall, there was some positive support but it ran out of steam because nobody could agree on how to handle NANs even though the IEEE-754 standard tells us how to handle them *wink*
See my responses at the time re NANs here:
https://mail.python.org/pipermail/python-ideas/2016-August/041439.html
https://mail.python.org/pipermail/python-ideas/2016-August/041400.html
https://mail.python.org/pipermail/python-ideas/2016-August/041396.html
Bottom line is that passing a NAN as the lower or upper bound should treat it as equivalent to "unbounded", that is, equivalent to ±∞.
That's not what the standard says. It's sorta connected to a personal opinion of Kahan's expressed in some work-in-progress lecture notes that you linked in the last message: https://people.eecs.berkeley.edu/~wkahan/ieee754status/IEEE754.PDF What he says there (on page 9) is
Some familiar functions have yet to be defined for NaN . For instance max{x, y} should deliver the same result as max{y, x} but almost no implementations do that when x is NaN . There are good reasons to define max{NaN, 5} := max{5, NaN} := 5 though many would disagree.
It's clear that he's not referring to standard behavior here and I'm not convinced that even he believes very strongly that min and max should behave that way. NaN means "there may be a correct answer but I don't know what it is." For example, evaluating (x**2+3*x+1)/(x+2) at x = -2 yields NaN. The correct answer to the problem that yielded this formula is probably -1, but because of the way floating point hardware works, it has no way of figuring that out. Likewise, the final result of a computation involving the square root of a negative real may be well defined, and may even be real, but the hardware can't compute it, so it "computes" NaN instead. It's definitely true that if plugging in any finite or infinite number whatsoever in place of a NaN will yield the same result, then that should be the result when you plug in a NaN. For example, clamp(x, NaN, x) should be x for every x (even NaN), and clamp(y, NaN, x) where y > x should be a ValueError (or however invalid bounds are treated). But, e.g., clamp(m, x, M) where m < x could yield any value between m and x, or a ValueError, depending on the value of M. So, if M is NaN, there is no way to know what the correct answer should be. Therefore (in my opinion) it should return NaN. There's a case for making clamp(m, x, NaN) where m >= x return m rather than NaN since there's no other *value* it could be (it could be an exception though).