Дроби с десятичной точностью
-
19-09-2019 - |
Вопрос
Существует ли чистая реализация Python fractions.Fraction
который поддерживает long
s как числитель и знаменатель?К сожалению, возведение в степень, похоже, закодировано для возврата числа с плавающей запятой (подтверждено!!!), что должно, по крайней мере, поддерживать использование 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'>
где ответ должен быть очень маленькой десятичной дробью.
Обновлять:На данный момент у меня есть следующий обходной путь (предполагая, что для a**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
класс достаточно, я найду и другие поплавки, которые войдут в мои результаты).
Решение
«Возведение в степень» не является замкнутой операцией над рациональными числами (в отличие от обычных четырех арифметических операций):нет рационального числа r
такой, что r == 2 ** 0.5
.Легенда гласит, что Пифагор (из теоремы которого так просто следует этот факт) приказал убить своего ученика Гиппаса за ужасное преступление, заключавшееся в доказательстве этого;похоже, вы сочувствуете предполагаемой реакции Пифагора ;-), учитывая ваше странное использование слова «должен».
Дроби Python должны быть точными, поэтому неизбежно возникают случаи, когда возведение дроби в степень другой дроби будет абсолютно недопустимо. не могущий вернуть дробь в качестве результата;и слово «должен» просто не может быть разумно применено к математической невозможности.
Поэтому лучшее, что вы можете сделать, это приблизительный желаемый результат, напримерполучая результат, который не является точной дробью (обычно для этой цели достаточно чисел с плавающей запятой), а затем дополнительно аппроксимируя его дробью.Большинство существующих реализаций на чистом Python (есть много rationals.py
файлы, найденные в сети ;-) предпочитают не реализовывать **
вообще, но вам, конечно, ничто не мешает принять другое дизайнерское решение в собственной реализации!-)
Другие советы
Вы можете написать свою собственную функцию «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 )