Сообщить об ошибке.

Рецепты работы с классом Decimal

Вот несколько рецептов, которые служат служебными функциями и демонстрируют способы работы с классом decimal.Decimal():

Преобразовать десятичную строку в строку формата денег:

from decimal import Decimal, getcontext

def moneyfmt(value, places=2, curr='', sep=',', dp='.',
             pos='', neg='-', trailneg=''):
    """Преобразование десятичной дроби в строку формата денег.

    places:  Требуемое количество знаков после запятой
    curr:    Необязательный символ валюты перед знаком (может быть пустым)
    sep:     Необязательный разделитель групп (запятая, точка, пробел или пусто)
    dp:      Индикатор десятичной точки (запятая или точка)
    pos:     Необязательный знак для положительных чисел: «+», пробел или пусто
    neg:     дополнительный знак для отрицательных чисел: '-', '(', пробел или пусто
    trailneg:опциональный трейлинг-минус: '-', ')', пробел или пусто

    >>> d = Decimal('-1234567.8901')
    >>> moneyfmt(d, curr='$')
    '-$1,234,567.89'
    >>> moneyfmt(d, places=0, sep='.', dp='', neg='', trailneg='-')
    '1.234.568-'
    >>> moneyfmt(d, curr='$', neg='(', trailneg=')')
    '($1,234,567.89)'
    >>> moneyfmt(Decimal(123456789), sep=' ')
    '123 456 789.00'
    >>> moneyfmt(Decimal('-0.02'), neg='<', trailneg='>')
    '<0.02>'

    """
    q = Decimal(10) ** -places      # 2 places --> '0.01'
    sign, digits, exp = value.quantize(q).as_tuple()
    result = []
    digits = list(map(str, digits))
    build, next = result.append, digits.pop
    if sign:
        build(trailneg)
    for i in range(places):
        build(next() if digits else '0')
    if places:
        build(dp)
    if not digits:
        build('0')
    i = 0
    while digits:
        build(next())
        i += 1
        if i == 3 and digits:
            i = 0
            build(sep)
    build(curr)
    build(neg if sign else pos)
    return ''.join(reversed(result))

Вычислить число Pi с текущей точностью:

from decimal import Decimal, getcontext

def pi():
    """Вычислить Pi с текущей точностью.

    >>> print(pi())
    3.141592653589793238462643383
    """
    getcontext().prec += 2  # extra digits for intermediate steps
    three = Decimal(3)      # substitute "three=3.0" for regular floats
    lasts, t, s, n, na, d, da = 0, three, 3, 1, 0, 0, 24
    while s != lasts:
        lasts = s
        n, na = n+na, na+8
        d, da = d+da, da+32
        t = (t * n) / d
        s += t
    getcontext().prec -= 2
    return +s               # unary plus applies the new precision

Возвести е в степень х. Тип результата соответствует типу ввода:

from decimal import Decimal, getcontext

def exp(x):
    """Получить е, возведенное в степень х. Тип результата соответствует типу ввода.

    >>> print(exp(Decimal(1)))
    2.718281828459045235360287471
    >>> print(exp(Decimal(2)))
    7.389056098930650227230427461
    >>> print(exp(2.0))
    7.38905609893
    >>> print(exp(2+0j))
    (7.38905609893+0j)

    """
    getcontext().prec += 2
    i, lasts, s, fact, num = 0, 0, 1, 1, 1
    while s != lasts:
        lasts = s
        i += 1
        fact *= i
        num *= x
        s += num / fact
    getcontext().prec -= 2
    return +s

Получить косинус х, измеренный в радианах:

from decimal import Decimal, getcontext

def cos(x):
    """Косинус `х`, измеренный в радианах

    Приближение ряда Тейлора работает лучше всего при небольшом значении x.
    Для больших значений сначала вычислите x = x % (2 * pi).

    >>> print(cos(Decimal('0.5')))
    0.8775825618903727161162815826
    >>> print(cos(0.5))
    0.87758256189
    >>> print(cos(0.5+0j))
    (0.87758256189+0j)

    """
    getcontext().prec += 2
    i, lasts, s, fact, num, sign = 0, 0, 1, 1, 1, 1
    while s != lasts:
        lasts = s
        i += 2
        fact *= i * (i-1)
        num *= x * x
        sign *= -1
        s += num / fact * sign
    getcontext().prec -= 2
    return +s

Получить синус х, измеренный в радианах:

from decimal import Decimal, getcontext

def sin(x):
    """Синус х, измеренный в радианах.

    Приближение ряда Тейлора работает лучше всего при небольшом значении x.
    Для больших значений сначала вычислите x = x % (2 * pi).

    >>> print(sin(Decimal('0.5')))
    0.4794255386042030002732879352
    >>> print(sin(0.5))
    0.479425538604
    >>> print(sin(0.5+0j))
    (0.479425538604+0j)

    """
    getcontext().prec += 2
    i, lasts, s, fact, num, sign = 1, 0, x, 1, x, 1
    while s != lasts:
        lasts = s
        i += 2
        fact *= i * (i-1)
        num *= x * x
        sign *= -1
        s += num / fact * sign
    getcontext().prec -= 2
    return +s