2010-01-10 6 views
6

Есть ли чистая реализация python fractions.Fraction, которая поддерживает long s как числитель и знаменатель? К сожалению, возведение в степень, по-видимому, закодировано, чтобы вернуть float (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, я найду другие поплавки, которые будут работать в моих результатах).

+0

Когда я делаю фракции. Фракция (11,17) ** 2 Я получаю фракции. Фракция (121, 289). Что вы получаете? –

+0

Тип попытки (фракции. Фракция (11,17) ** 2.1) – Noah

+0

ИМО, поведение, которое вы видите правильно, хотя и не то, что вы хотите.Поскольку показатель степени является float, разумно, что вещи преобразуются в float. Теперь, если показателем была фракция (21,10), это было бы более интересно ... –

ответ

6

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

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

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

+0

Это, конечно, правильно математически, но причина, по которой я использую класс фракций, состоит в том, что я хочу высокую численную точность, и я пытаюсь обновить код кто-то написал с использованием библиотеки clnum. Поскольку фракция счастлива взять длинный как числитель или знаменатель, кажется справедливым, что он должен иметь возможность вернуть десятичное число после возведения в степень. Теперь, если бы я мог выяснить, должен ли fracpow (0,0) быть определен как 1, или если это была ошибка в коде! – Noah

+1

@Noah, не может реально помочь вам с чистым кодом Python, потому что для таких задач я всегда использую 'gmpy', конечно; но gmpy.mpq не допускает inexact-корней с дробными показателями либо (_my_ дизайнерское решение в этом случае), поэтому я бы прошел через высокоточные поплавки (gmpy.mpf в моем случае) так же, как вы делаете с Decimal (которые также являются поплавками, а скорее десятичными, а не двоичными, с SW, а не HW-реализациями, и с точностью, устанавливаемой как можно выше - gmpy.mpf похожи, но двоичные, а не десятичные). –

+0

Ошибка из вашего численного приближения exp будет обычно больше, чем ошибка аппроксимации результата аппроксимации с помощью float. –

0

Вы можете написать свою собственную функцию «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) 
+0

Хм, лучше иметь базовый случай _some_, чтобы закончить рекурсию в конце концов! -) –

Смежные вопросы