具有小数精度的分数
有没有一个纯Python实现的fractions.Fraction
,可以支持long
类型作为分子和分母?不幸的是,指数运算似乎是写死的,返回的是浮点数(哎呀!),这至少应该支持使用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_是浮点数或本身是Decimal时,我需要另一个函数):
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 个回答
你可以自己写一个“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 )
"提升到某个幂"这个操作在有理数中并不是一个封闭的操作(和我们平常的四则运算不一样):没有一个有理数r
能满足r == 2 ** 0.5
。传说中,毕达哥拉斯(这个定理就是由他提出的)因为他的弟子希帕苏斯证明了这一点而把他杀了;看起来你对毕达哥拉斯的反应很有同感,毕竟你用“应该”这个词的方式有点奇怪;-)
Python中的分数是为了精确计算而设计的,所以不可避免地会出现一些情况,提升一个分数到另一个分数的幂时,结果根本无法返回一个分数;而“应该”这个说法在数学上是不可能的事情上是没法成立的。
所以你能做的最好的事情就是近似你想要的结果,比如得到一个不是精确分数的结果(浮点数通常被认为足够用),然后再用分数进一步近似。大多数现有的纯Python实现(网上有很多rationals.py
文件;-))都不太愿意实现**
这个操作符,但当然你可以在自己的实现中做出不同的设计决定!-)