On Sat, Jul 04, 2020 at 11:54:47AM -0700, Christopher Barker wrote:
> Hmm.
>
>
> Since NaN is neither greater than nor less that anything, it seems the only
> correct answer to any
> Min,max,clamp involving a NaN is NaN.
If you want NAN-poisoning behaviour it is easy for you to add it
yourself as a wrapper function, without it costing any more than it
would cost to have that behaviour baked into the function. You get to
choose if you want to handle floats only, or Decimals, or both, what to
do with signalling NANs, or whether to bother at all. If you know your
bounds are not NANs, why test for them at all?
But if you bake special NAN poisoning behaviour in to the function,
nobody can escape it. Everyone has to test for NANs, whether they need
to or not, and worse, if they want non-poisoned behaviour, they have to
test for NANs *twice*, once to over-ride the builtin behaviour, and then
a second time when they call the function.
When we have a choice of behaviours and no absolutely clear right or
wrong choice, we should choose the behaviour that inconveniences people
the least.
The beauty of the implementation I give is that the behaviour with NANs
follows automatically, without needing to test for them. NAN poisoning
requires testing for NANs, and that is not so easy to get right:
py> math.isnan(2**10000)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OverflowError: int too large to convert to float
py> math.isnan(Decimal('sNAN'))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: cannot convert signaling NaN to float
You want everyone to pay the cost of testing for NANs, even if they
don't want or need to. I say, let only those who need to test for NANs
actually test for NANs.
Why is this a debate we need to have?
In practice, the most common use-case for clamp will be to call it
multiple times against different values but with the same bounds:
# Not likely to be this
for value in values:
lower = something_different_each_time()
upper = something_different_each_time()
do_something(clamp(value, lower, upper))
# Most commonly this:
for value in values:
do_something(clamp(value, lower, upper))
If you care about the remote possibility of the bounds being NANs, and
want to return NAN instead, hoist the test outside of the call:
# TODO: Need to catch OverflowError, maybe ValueError
# maybe even TypeError?
if math.isnan(lower) or math.isnan(upper):
for value in values:
do_something(NAN)
else:
for value in values:
do_something(clamp(value, lower, upper))
and you only pay the cost once. Don't make everyone pay it over and over
and over again when the bounds are known to not be NANs.
--
Steven
_______________________________________________
Python-ideas mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at
https://mail.python.org/archives/list/[email protected]/message/7RK5TSYDI6N4OUJ4SOSKWEYPHAPQFIFA/
Code of Conduct: http://python.org/psf/codeofconduct/