On Mon, Jul 06, 2020 at 12:59:28PM +1200, Greg Ewing wrote:
I agree with you that `clamp(lower=x, value=NAN, upper= x)` should return x.
I don't think I agree with that
Sorry Greg, on this point at least the IEEE-754 standard is firm: if a function will return the same result for every non-NAN argument, then it must return the same result for NAN arguments too. clamp(value, x, x) will always return x for every finite and infinite value, so it must return x for NANs too. Quoting one of the standard committee members: NaN must not be confused with “Undefined.” On the contrary, IEEE 754 defines NaN perfectly well even though most language standards ignore and many compilers deviate from that definition. The deviations usually afflict relational expressions, discussed below. Arithmetic operations upon NaNs other than SNaNs (see below) never signal INVALID, and always produce NaN unless replacing every NaN operand by any finite or infinite real values would produce the same finite or infinite floating-point result independent of the replacements. https://people.eecs.berkeley.edu/~wkahan/ieee754status/IEEE754.PDF See page 7. This is why 1.0**NAN returns 1.0, and why math.hypot(INF, NAN) returns INF.
because it relies on assuming that the lower and upper bounds can meaningfully be compared for exact equality, which may not be true depending on the circumstances.
I don't understand that objection. Can you give a concrete example?
Treat a NAN bounds as *missing data*, which effectively means "there is no limit", i.e. as if you had passed the infinity of the appropriate sign for the bounds.
If one of the bounds is missing, you don't need clamp(), you can use min() or max().
Only if you know it is missing. If the bounds come from some other calculation or from the user, how do you know they are missing? if lower is upper is None: pass elif lower is None: value = min(value, upper) elif upper is None: value = max(value, lower) else: value = clamp(value, lower, upper) We don't have three slice functions to cover the cases where one or the other bounds is missing: slice(start, stop) slice_end_at(stop) slice_start_at(start) we just have a single function that takes a missing value. -- Steven