Apologies for the bad formatting. Here's a repost with shorter lines.<div><br class="webkit-block-placeholder"></div><div><br class="webkit-block-placeholder"></div><div>Dear all,</div><div><br class="webkit-block-placeholder">
</div><div>I'd like to draw your attention to some of the work that's been going on in</div><div>the trunk-math branch. Christian Heimes and I have been working on various</div><div>aspects of Python mathematics, and we're hoping to get at least some of this</div>
<div>work into Python 2.6/3.0. Most of the changes are completed or nearly</div><div>complete, and 2.6/3.0 isn't very far away, so it seems like a good time to</div><div>try to get some feedback from python-dev.</div>
<div><div class="gmail_quote"><div> </div><div>Here's an overview of the changes (overview originally written by Christian,</div><div>edited and augmented by me. I hope Christian will step in and correct me if</div><div>
I misrepresent him or his work here.) Many of the changes were motivated by</div><div>Christian's work (already in the trunk) in making infinities and nans more</div><div>accessible and portable for Python users. (See issue #1640.)</div>
<div> </div><div>* Structural reorganization: there are new files Include/pymath.h and</div><div>Objects/pymath.c with math-related definitions and replacement functions for</div><div>platforms without copysign, log1p, hypot and inverse hyperbolic functions.</div>
<div><br class="webkit-block-placeholder"></div><div>* New math functions: inverse hyperbolic functions (acosh, asinh, atanh).</div><div> </div><div>* New float methods: is_finite, is_inf, is_integer and is_nan.</div><div>
<br class="webkit-block-placeholder"></div><div>* New cmath functions: phase, polar and rect, isinf and isnan.</div><div><br class="webkit-block-placeholder"></div><div>* New complex method: is_finite.</div><div><br class="webkit-block-placeholder">
</div><div>* Work on math and cmath functions to make them handle special values</div><div>(infinities and nans) and floating-point exceptions according to the C99</div><div>standard. The general philosophy follows the ideas put forth by Tim Peters</div>
<div>and co. many moons ago. and repeated in the issue #1640 thread more</div><div>recently: where the C99 standard (or IEEE 754) specifies raising 'invalid'</div><div>or 'divide-by-zero' Python should raise a ValueError. Where the C99</div>
<div>standard specifies raising 'overflow' Python should raise OverflowError.</div><div>'underflow' and 'inexact' flags are ignored. From a user's perspective,</div><div>this means that infinities and nans are never produced by math or cmath</div>
<div>operations on finite values (but see below). sqrt(-1) will always raise</div><div>ValueError, instead of returning a NaN. See issue #711019 and the resulting</div><div>warning at the bottom of the math module documentation. Although</div>
<div>complex_abs doesn't live in cmathmodule.c, it was also fixed up this way.</div><div><br class="webkit-block-placeholder"></div><div>* The cmath module has been rescued: it's no longer numerically unsound</div>
<div>(see issue #1381). For the majority of functions (sin, cos, tan, sinh,</div><div>cosh, tanh, asin, acos, atan, asinh, acosh, atanh, exp, sqrt) the real and</div><div>imaginary parts of the results are always within a few ulps of the true</div>
<div>values. (In extensive but non-exhaustive testing I haven't found errors of</div><div>more than 5 ulps in either the real or imaginary parts for these functions.)</div><div>For log and log10 the errors can be larger when the argument has absolute</div>
<div>value close to 1; this seems pretty much unavoidable without using</div><div>multiple-precision arithmetic. pow and two-argument log are less accurate;</div><div>again, this is essentially unavoidable without adding hundreds of extra</div>
<div>lines of code.</div><div><br class="webkit-block-placeholder"></div><div>* Many more tests. In addition to a handful of extra test_* methods in</div><div>test_math and test_cmath, there are over 1700 testcases (in a badly-named</div>
<div>file Lib/test/cmath.ctest) for the cmath and math functions, with a testcase</div><div>format inspired in no small part by the decimal .decTest file format. Most</div><div>of the testcase values were produced independently of Python using MPFR and</div>
<div>interval arithmetic (C code available on request); some were created by</div><div>hand.</div><div> </div><div>* There's a per-thread state for division operator. In IEEE 754 mode 1./0.</div><div>and 1.%0. return INF and 0./0. NAN. The contextlib has a new context</div>
<div>"ieee754" and the math lib set_ieee754/get_ieee754 (XXX better place for the</div><div>functions?)</div><div><br class="webkit-block-placeholder"></div><div>Some notes:<br></div><div><br class="webkit-block-placeholder">
</div><div>* We've used the C99 standard (especially Annex F and Annex G) as a</div><div>reference for deciding what the math and cmath functions should do, wherever</div><div>possible. It seems to make sense to choose to follow some standard,</div>
<div>essentially so that all the hard decisions have been thought through</div><div>thoroughly by a group of experts. Two obvious choices are the C99 standard</div><div>and IEEE 754(r); for almost all math issues the two say essentially the same</div>
<div>thing. C99 has the advantage that it includes specifications for complex</div><div>math, while IEEE 754(r) does not. (Actually, I've been using draft version</div><div>N1124 of the C99 standard, not the standard itself, since I'm too cheap to</div>
<div>pay up for a genuine version. Google 'N1124' for a copy.)</div><div> </div><div>* I'm offering to act as long-term maintainer for the cmath module, if</div><div>that's useful.</div><div> </div><div>* The most interesting and exciting feature, by far (in my opinion) is the</div>
<div>last one. By way of introduction, here's a snippet from Tim Peters, in a</div><div>comp.lang.python posting</div><div>(<a href="http://mail.python.org/pipermail/python-list/2005-July/330745.html" target="_blank">http://mail.python.org/pipermail/python-list/2005-July/330745.html</a>),</div>
<div>answering a question from Michael Hudson about 1e300*1e300 and inf/inf.</div><div> </div><div>"I believe Python should raise exceptions in these cases by default,</div><div>because, as above, they correspond to the overflow and invalid-operation</div>
<div>signals respectively, and Python should raise exceptions on the overflow,</div><div>invalid-operation, and divide-by-0 signals by default. But I also believe</div><div>Python _dare not_ do so unless it also supplies sane machinery for disabling</div>
<div>traps on specific signals (along the lines of the relevant standards here).</div><div>Many serious numeric programmers would be livid, and justifiably so, if they</div><div>couldn't get non-stop mode back. The most likely x-platfrom accident so far</div>
<div>is that they've been getting non-stop mode in Python since its beginning."</div><div> </div><div>Christian has found a simple, elegant and practical way to make it possible</div><div>for Python to raise these exceptions by default, while also allowing serious</div>
<div>numeric users access to non-stop mode---i.e., a mode that generates inf from</div><div>1/0 instead of raising a Python exception. (I had a much more elaborate</div><div>plan in mind, involving a thread-local context similar to Decimal's, with</div>
<div>control over individual traps and flags. Christian's solution is far more</div><div>practical.) The idea is that any arithmetic operating under a "with</div><div>ieee754:" acts like arithmetic on an IEEE 754 platform with no traps</div>
<div>enabled: invalid operations like sqrt(-1) produce a nan, division by zero</div><div>produces an infinity, etc. No Python exceptions related to floating-point</div><div>are raised.</div><div> </div><div>See the thread started by Neal Becker at<a href="http://mail.python.org/pipermail/python-list/2008-February/477064.html" target="_blank"></a></div>
<div><a href="http://mail.python.org/pipermail/python-list/2008-February/477064.html" target="_blank">http://mail.python.org/pipermail/python-list/2008-February/477064.html</a></div><div>entitled "Turn off ZeroDivisionError?" for a recent discussion of these</div>
<div>issues.</div><div> </div><div>I fear that the per-thread state change seems like something where a PEP</div><div>might be necessary; it's also not clear right now that Christian and I have</div><div>exactly the same goals here (discussion is ongoing). But I hope that the</div>
<div>rest of the changes are uncontroversial enough to merit consideration for</div><div>possible inclusion in 2.6/3.0.</div><div> </div><div>Thoughts?</div><div> </div><div>Mark</div><div><br></div></div></div>