15.4. The decimal ModuleA Python float is a binary floating-point number, normally in accordance with the standard known as IEEE 754 and implemented in hardware in modern computers. A concise, practical introduction to floating-point arithmetic and its issues can be found in David Goldberg's essay "What Every Computer Scientist Should Know about Floating-Point Arithmetic," at http://docs.sun.com/source/806-3568/ncg_goldberg.html. Often, particularly for money-related computations, you may prefer to use decimal floating-point numbers; Python 2.4 supplies an implementation of the standard known as IEEE 854, for base 10, in standard library module decimal. At http://docs.python.org/lib/module-decimal.html, you can find complete reference documentation, pointers to the applicable standards, a tutorial, and an advocacy for decimal. Here, I cover only a small subset of decimal's functionality that corresponds to the most frequently used parts of the module. Module decimal supplies a class Decimal whose immutable instances are decimal numbers, exception classes, and classes and functions to deal with the arithmetic context, which specifies such things as precision, rounding, and which computational anomalies (such as division by zero, overflow, underflow, and so on) will raise exceptions if they occur. In the default context, precision is 28 decimal digits, rounding is "half-even" (round results to the closest representable decimal number: when a result is exactly halfway between two such numbers, round to the one whose last digit is even), and anomalies that raise exceptions are invalid operation, division by zero, and overflow. To build a decimal number, call decimal.Decimal with one argument: an integer or a string. If you start with a float, you must pass to Decimal a string form of that float to control all the digits involved. For example, decimal.Decimal(0.1) is an error; use decimal.Decimal('0.1') (try decimal.Decimal(repr(0.1)) to help you understand why, and see http://python.org/doc/2.4.2/tut/node16.html for a detailed explanation of the issues). If you wish, you can easily write a factory function for ease of experimentation, particularly interactive experimentation, with decimal: import decimal def d(x): return decimal.Decimal(str(x)) Now d(0.1) is just the same thing as decimal.Decimal('0.1'), but far more concise and thus handier to write. Once you have instances of decimal, you can perform arithmetic among them (and with integers, but not with floats), pickle and unpickle them, use them as keys in dictionaries and members of sets, and format them (with a string's % operator, covered in "String Formatting" on page 193) with the same formatting choices that are available for floats; however, in the latter cases (just as if you pass them as arguments to functions in module math, say) the instances of decimal get converted into floats, which implies a loss of precision. See http://docs.python.org/lib/decimal-recipes.html for some useful recipes for more precise formatting and trigonometric computations. |