Welcome, guest | Sign In | My Account | Store | Cart

Evaluate using Decimals instead of floats.

Python, 18 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
import re
number_pattern = re.compile(r"((\A|(?<=\W))(\d+(\.\d*)?|\.\d+)([eE][+-]?\d+)?)")

def deciexpr(expr):
    """Substitute Decimals for floats in an expression string.

    >>> from decimal import Decimal
    >>> s = '+21.3e-5*85-.1234/81.6'
    >>> deciexpr(s)
    "+Decimal('21.3e-5')*Decimal('85')-Decimal('.1234')/Decimal('81.6')"

    >>> eval(s)
    0.016592745098039215
    >>> eval(deciexpr(s))
    Decimal("0.01659274509803921568627450980")

    """
    return number_pattern.sub(r"Decimal('\1')", expr)

The numeric part of the regular expression is a direct translation from the decimal module's docs for Decimal object. See section 2 at http://docs.python.org/lib/module-decimal.html

For clarity, the regular expression does not scan for NaNs and Infinities. Those are trivial to incorporate if necessary.

Note, the optional leading sign is excluded from the pattern -- this is consistent with what Python does for other numeric literals (-0.1 lexes as a unary minus operation on 0.1). See http://docs.python.org/ref/numbers.html

The token separator part of the regular expression assures that numbers either start at the beginning of the string or are preceded by a single non-alphanumeric character. This prevents spurious mistranslations of valid Python identifiers such as vec1, vec2, etc.

Created by Raymond Hettinger on Tue, 29 Mar 2005 (PSF)
Python recipes (4591)
Raymond Hettinger's recipes (97)

Required Modules

Other Information and Tasks