Recipe3.12.Doing Decimal Arithmetic


Recipe 3.12. Doing Decimal Arithmetic

Credit: Anna Martelli Ravenscroft

Problem

You want to perform some simple arithmetic computations in Python 2.4, but you want decimal results, not the Python default of float.

Solution

To get the normal, expected results from plain, simple computations, use the decimal module introduced in Python 2.4:

>>> import decimal >>> d1 = decimal.Decimal('0.3')   # assign a decimal-number object >>> d1/3                          # try some division Decimal("0.1") >>> (d1/3)*3                      # can we get back where we started? Decimal("0.3")

Discussion

Newcomers to Python (particularly ones without experience with binary float calculations in other programming languages) are often surprised by the results of seemingly simple calculations. For example:

>>> f1 = .3                     # assign a float >>> f1/3                        # try some division 0.099999999999999992 >>> (f1/3)*3                    # can we get back where we started? 0.29999999999999999

Binary floating-point arithmetic is the default in Python for very good reasons. You can read all about them in the Python FAQ (Frequently Asked Questions) document at http://www.python.org/doc/faq/general.html#why-are-floating-point-calculations-so-inaccurate, and even in the appendix to the Python Tutorial at http://docs.python.org/tut/node15.html.

Many people, however, were unsatisfied with binary floats being the only optionthey wanted to be able to specify the precision, or wanted to use decimal arithmetic for monetary calculations with predictable results. Some of us just wanted the predictable results. (A True Numerical Analyst does, of course, find all results of binary floating-point computations to be perfectly predictable; if any of you three are reading this chapter, you can skip to the next recipe, thanks.)

The new decimal type affords a great deal of control over the context for your calculations, allowing you, for example, to set the precision and rounding method to use for the results. However, when all you want is to run simple arithmetical operations that return predictable results, decimal's default context works just fine.

Just keep in mind a few points: you may pass a string, integer, tuple, or other decimal object to create a new decimal object, but if you have a float n that you want to make into a decimal, pass str(n), not bare n. Also, decimal objects can interact (i.e., be subject to arithmetical operations) with integers, longs, and other decimal objects, but not with floats. These restrictions are anything but arbitrary. Decimal numbers have been added to Python exactly to provide the precision and predictability that float lacks: if it was allowed to build a decimal number from a float, or by operating with one, the whole purpose would be defeated. decimal objects, on the other hand, can be coerced into other numeric types such as float, long, and int, just as you would expect.

Keep in mind that decimal is still floating point, not fixed point. If you want fixed point, take a look at Tim Peter's FixedPoint at http://fixedpoint.sourceforge.net/. Also, no money data type is yet available in Python, although you can look at Recipe 3.13 to learn how to roll-your-own money formatting on top of decimal. Last but not least, it is not obvious (at least not to me), when an intermediate computation produces more digits than the inputs, whether you should keep the extra digits for further intermediate computations, and round only when you're done computing a formula (and are about to display or store a result), or whether you should instead round at each step. Different textbooks suggest different answers. I tend to do the former, simply because it's more convenient.

If you're stuck with Python 2.3, you may still take advantage of the decimal module, by downloading and installing it as a third-party extensionsee http://www.taniquetil.com.ar/facundo/bdvfiles/get_decimal.html.

See Also

The explanation of floating-point arithmetic in Appendix B of the Python Tutorial at http://docs.python.org/tut/node15.html; the Python FAQ at http://www.python.org/doc/faq/general.html#why-are-floating-point-calculations-so-inaccurate; Tim Peter's FixedPoint at http://fixedpoint.sourceforge.net/; using decimal as currency, see Recipe 3.13; decimal is documented in the Python 2.4 Library Reference and is available for download to use with 2.3 at http://cvs.sourceforge.net/viewcvs.py/python/python/dist/src/Lib/decimal.py; the decimal PEP (Python Enhancement Proposal), PEP 327, is at http://www.python.org/peps/pep-0327.html.



Python Cookbook
Python Cookbook
ISBN: 0596007973
EAN: 2147483647
Year: 2004
Pages: 420

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net