Why `divmod(float('inf'), 1) == (float('nan'), float('nan'))`

wxjmfauth at gmail.com wxjmfauth at gmail.com
Thu Sep 18 08:57:17 EDT 2014


Le jeudi 18 septembre 2014 11:26:14 UTC+2, Steven D'Aprano a écrit :
> Marko Rauhamaa wrote:
> 
> 
> 
> > Maybe IEEE had some specific numeric algorithms in mind when it
> 
> > introduced inf and nan. However, I have a feeling an exception would be
> 
> > a sounder response whenever the arithmetics leaves the solid ground.
> 
> 
> 
> I'm afraid that you're missing the essential point of INF and quiet NANs,
> 
> namely that they *don't* cause an exception. That is their point.
> 
> 
> 
> Back in the Dark Ages of numeric computing, prior to IEEE-754, all was
> 
> chaos. Numeric computing was a *mess*. To give an example of how bad it
> 
> was, there were well-known computers where:
> 
> 
> 
>     x != 0
> 
> 
> 
> would pass, but then:
> 
> 
> 
>     1.0/x
> 
> 
> 
> would fail with a Division By Zero error (which could mean a segfault).
> 
> Another machine could have 1.0*x overflow; a whole class of IBM machines
> 
> had 1.0*x lop off one bit of precision each time you called it, so that
> 
> multiplying by one would gradually and irreversibly change the number. Chip
> 
> designers had a cavalier attitude towards the accuracy of floating point
> 
> arithmetic, preferring to optimise for speed even when the result was
> 
> wrong. Writing correct, platform-independent floating point code was next
> 
> to impossible.
> 
> 
> 
> When IEEE-754 was designed, the target was low-level languages similar to C,
> 
> Pascal, Algol, Lisp, etc. There were no exceptions in the Python sense, but
> 
> many platforms provided signals, where certain operations could signal an
> 
> exceptional case and cause an interrupt. IEEE-754 standardised those
> 
> hardware-based signals and required any compliant system to provide them.
> 
> 
> 
> But it also provided a mechanism for *not* interrupting a long running
> 
> calculation just because an exception occurred. Remember that not all
> 
> exceptions are necessarily fatal. You can choose whether exceptions in a
> 
> calculation will cause a signal, or quietly continue. It even defines two
> 
> different kinds of NANs, signalling and quiet NANs: signalling NANs are
> 
> supposed to signal, always, and quiet NANs are supposed to either silently
> 
> propagate or signal, whichever you choose.
> 
> 
> 
> Instead of peppering your code with dozens, even hundreds of Look Before You
> 
> Leap checks for error conditions, or installing a single signal handler
> 
> which will catch exceptions from anywhere in your application, you have the
> 
> choice of also allowing calculations to continue to the end even if they
> 
> reach an exceptional case. You can then inspect the result and decide what
> 
> to do: report an error, re-do the calculation with different values, skip
> 
> that iteration, whatever is appropriate.
> 
> 
> 
> The standard even gives NANs a payload, so that they can carry diagnostic
> 
> information. For instance, NAN[1] might mean 0/0, while NAN[2] might mean
> 
> INF-INF. The Standard Apple Numerics Environment (SANE) in the 1980s and
> 
> 90s supported that, and it worked really well. Alas, I don't know any other
> 
> language or library that even offers a way to inspect the NAN payload, let
> 
> alone promises to set it consistently.
> 
> 
> 
> In any case, other error handling strategies continue to work, or at least
> 
> they are supposed to work.
> 
> 
> 
> A good way to understand how the IEEE-754 standard is supposed to work is to
> 
> read and use the decimal.py module. (Strictly speaking, decimal doesn't
> 
> implement IEEE-754, but another, similar, standard.) Python's binary
> 
> floats, which are a thin wrapper around the platform C libraries, is sad
> 
> and impoverished compared to what IEEE-754 offers.
> 
> 
> 
> 

>>> def docalc1(i):
...     if i == 0:
...         t = 1 / 0
...     else:
...         return float('inf')
...         
>>> try:
...     r = docalc1(1)
...     if math.isinf(r):
...         print('do something because inf')
... except ZeroDivisionError:
...     print('do something else because error is raised')
...     
do something because inf
>>> try:
...     r = docalc1(0)
...     if math.isinf(r):
...         print('do something because inf')
... except ZeroDivisionError:
...     print('do something else because error is raised')
...     
do something else because error is raised


Annoying. One does not know the result *before*
executing any calculations.

jmf



More information about the Python-list mailing list