Фракции с десятичной точностью - PullRequest
6 голосов
/ 11 января 2010

Существует ли чистая реализация Python fractions.Fraction, которая поддерживает long s в качестве числителя и знаменателя? К сожалению, возведение в степень, по-видимому, закодировано, чтобы вернуть число с плавающей точкой (ack !!!), которое должно по крайней мере поддерживать использование decimal.Decimal.

Если нет, то, вероятно, я могу сделать копию библиотеки и попытаться заменить вхождения float() на что-то подходящее из Decimal, но я бы предпочел что-то, что было проверено другими ранее.

Вот пример кода:

base = Fraction.from_decimal(Decimal(1).exp())
a = Fraction(69885L, 53L)
x = Fraction(9L, 10L)

print base**(-a*x), type(base**(-a*x))

приводит к 0.0 <type 'float'>, где ответ должен быть действительно небольшим десятичным знаком.

Обновление : на данный момент у меня есть следующий обходной прием (при условии, что для ** b оба являются дробями; конечно, мне понадобится другая функция, когда exp_ является плавающей точкой или является десятичным числом):

def fracpow(base, exp_):
    base = Decimal(base.numerator)/Decimal(base.denominator)
    exp_ = Decimal(exp_.numerator)/Decimal(exp_.denominator)

    return base**exp_

, который дает ответ 4.08569925773896097019795484811E-516.

Мне все равно было бы интересно, есть ли лучший способ сделать это без дополнительных функций (полагаю, если я буду работать с классом Fraction, я найду другие поплавки, которые будут влиять на мои результаты) .

Ответы [ 2 ]

6 голосов
/ 11 января 2010

«Поднять в степень» не является закрытой операцией над рациональными числами (в отличие от обычных четырех арифметических операций): рационального числа r не существует, такого, что r == 2 ** 0.5. Легенда гласит, что Пифагор (из теоремы которого этот факт так просто вытекает) убил своего ученика Гиппаса за ужасное преступление, доказавшее это; похоже, вы сочувствуете остроумной реакции Пифагора ;-), учитывая ваше странное употребление слова «следует».

Дроби Python должны быть точными, поэтому неизбежно возникает случай, когда возведение дроби в степень другой дроби будет абсолютно неспособным вернуть дробь в качестве результата; и «должен» просто не может быть разумно применен к математической невозможности.

Итак, лучшее, что вы можете сделать, - это приблизительный желаемый результат, например. получая результат, который не является точной дробью (поплавки обычно считаются достаточными для этой цели), а затем дополнительно аппроксимируя его обратно дробью. Большинство существующих реализаций на чистом Python (в сети есть много rationals.py файлов ;-) предпочитают вообще не реализовывать оператор **, но, конечно, ничто не мешает вам сделать другое дизайнерское решение в собственном исполнении! -)

0 голосов
/ 11 января 2010

Вы можете написать свою собственную функцию "pow" для дробей, которые не используют возведение в степень с плавающей точкой. Это то, что вы пытаетесь сделать?

Это увеличит дробную часть до целочисленной степени с обратным всплытием.

def pow( fract, exp ):
    if exp == 0: 
        return fract
    elif exp % 2 == 0:
        t = pow( fract, exp//2 )
        return t*t
    else:
        return fract*pos( fract, exp-1 )
...