On Mon, 06 Jun 2011 14:11:03 +1000, Chris Angelico wrote: > On Mon, Jun 6, 2011 at 11:21 AM, Steven D'Aprano > <steve+comp.lang.pyt...@pearwood.info> wrote: >> The intended behaviour is operations on "quiet NANs" should return >> NANs, but operations on "signalling NANs" should cause a trap, which >> can either be ignored, and converted into a quiet NAN, or treated as an >> exception. >> >> E.g. in Decimal: [snip] > > So does this mean that: > > a = 0.0/0.0 > b = a + 1 > > (with signalling NANs) should trap on the second line but not the first? > That's the first "operation on a nan".
Sort of. Firstly, in order for a = 0.0/0.0 to not trap (not raise an exception), you have to tell it not to trap InvalidOperation (and DivideByZero I think?). So using Decimal: >>> import decimal >>> decimal.getcontext() Context(prec=9, rounding=ROUND_HALF_UP, Emin=-999999999, Emax=999999999, capitals=1, flags=[], traps=[Underflow, Clamped, DivisionByZero, Overflow, InvalidOperation]) If we call Decimal(0)/Decimal(0), it will be trapped, which is treated as an exception in Python. To get a NAN: >>> decimal.setcontext(decimal.ExtendedContext) >>> decimal.getcontext() Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999999, Emax=999999999, capitals=1, flags=[], traps=[]) >>> >>> D = decimal.Decimal >>> a = D(0)/D(0) >>> a Decimal('NaN') Note that a flag is set, so you can tell that an exceptional event has occurred: >>> decimal.getcontext() Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999999, Emax=999999999, capitals=1, flags=[InvalidOperation], traps=[]) But the NAN given is a quiet NAN. Doing further operations on it doesn't trap: >>> decimal.getcontext().traps[decimal.InvalidOperation] = 1 >>> decimal.getcontext().flags.clear() >>> b = a + 1 >>> decimal.getcontext() Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999999, Emax=999999999, capitals=1, flags=[], traps=[InvalidOperation]) However, if you use a signalling NAN, the situation is different. As far as I can tell, the only way to get a signalling NAN is to create one yourself: >>> c = D('sNAN') >>> d = c + 1 Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/lib/python2.6/decimal.py", line 1064, in __add__ ans = self._check_nans(other, context) File "/usr/local/lib/python2.6/decimal.py", line 703, in _check_nans self) File "/usr/local/lib/python2.6/decimal.py", line 3778, in _raise_error raise error(explanation) decimal.InvalidOperation: sNaN I don't think that there's any way to tell IEEE-754 for operations on NANs to return signalling NANs. As I understand it, the idea is: - if you want exceptions to signal, set the appropriate traps; - if you want NANs that propagate through your calculation, clear the traps and you'll get propagating NANs; - if you need to detect the presence of a NAN in your calculation, you can inspect the flags at any time and take whatever action you want; - and if you want a signalling NAN, you have to inject it yourself into your calculation, and then avoid using it. I'm lead to believe that signalling NANs were added to satisfy politics, but apart from being slightly useful for marking uninitialised memory before use, nobody actually uses them in practice. Wanna see something cool? You can check for inexact arithmetic: >>> decimal.getcontext().flags {<class 'decimal.InvalidOperation'>: 1} >>> D(1)/D(7) Decimal('0.142857143') >>> decimal.getcontext().flags {<class 'decimal.Inexact'>: 1, <class 'decimal.InvalidOperation'>: 1, <class 'decimal.Rounded'>: 1} and trap on it: >>> decimal.getcontext().traps[decimal.Inexact] = 1 >>> D(1)/D(7) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/lib/python2.6/decimal.py", line 1275, in __truediv__ return ans._fix(context) File "/usr/local/lib/python2.6/decimal.py", line 1632, in _fix context._raise_error(Inexact) File "/usr/local/lib/python2.6/decimal.py", line 3778, in _raise_error raise error(explanation) decimal.Inexact: None Not surprisingly, by default that's turned off :) -- Steven -- http://mail.python.org/mailman/listinfo/python-list