小数精度的分数

7
有没有纯Python实现的fractions.Fraction,支持长整型作为分子和分母?不幸的是,指数运算似乎已经编码返回了浮点数(啊!),至少应该支持使用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类一起使用足够长时间,其他浮点数也会出现在我的结果中)。


当我执行 fractions.Fraction(11,17) ** 2 时,我得到了 fractions.Fraction(121, 289)。你得到了什么? - President James K. Polk
尝试输入(fractions.Fraction(11,17)**2.1)。 - Noah
在我看来,你所看到的行为是正确的,尽管不是你想要的。由于指数是浮点数,因此将事物转换为浮点数是合理的。现在,如果指数是Fraction(21,10),那就更有趣了... - President James K. Polk
请查看上面更新的代码,其中指数实际上是一个分数。 - Noah
2个回答

7
"乘方"在有理数上不是封闭运算(与通常的四则运算不同):没有有理数,使得 == 2 ** 0.5。传说中,毕达哥拉斯(这个事实如此简单地遵循了他的定理)杀死了他的门徒希帕索斯,因为他证明了这个可怕的罪行;看起来你同情毕达哥拉斯的所谓反应;-),鉴于你奇怪的使用“should”。
Python的分数旨在精确,因此不可避免地会出现一些情况,将一个分数提高到另一个分数的幂时将绝对无法返回一个分数作为其结果;而“should”在数学上是不可行的。
因此,您能做的最好的事情就是逼近您所需的结果,例如通过获得不是精确分数的结果(浮点数通常被认为足够),然后再用分数进一步逼近它。大多数现有的纯Python实现(在网络上发现了许多rationals.py文件)都不愿实现**运算符,但当然,您可以在自己的实现中做出不同的设计决策!-)

这在数学上当然是正确的,但我使用Fraction类的原因是我想要高精度数字,并且我正在尝试更新其他人使用clnum库编写的代码。由于Fraction可以将长整型作为分子或分母,所以它应该能够在指数运算时返回一个Decimal。现在,如果我能弄清楚fracpow(0,0)是否应定义为1,或者那是代码中的错误,那就好了! - Noah
1
@Noah,我无法为你提供纯Python代码的帮助,因为对于这样的任务,我总是使用gmpy;但是gmpy.mpq也不允许使用分数指数进行非精确根(在这种情况下是我的设计决策),所以我会通过高精度浮点数(在我的情况下是gmpy.mpf)来完成,就像你用Decimal一样(它们也是浮点数,只是十进制而不是二进制,具有可设置为所需精度的软件实现,而不是硬件实现--gmpy.mpf类似,但是是二进制而不是十进制)。 - Alex Martelli
你的数值逼近exp的误差通常比用浮点数逼近逼近结果的误差要大。 - quant_dev
如果2 ** 0.5证明了在所有情况下都应该使用float而不是fractions.Fraction,那么为什么(-1) ** 0.5不证明在所有情况下都应该使用complex - jfs
@quant_dev,当然你可以计算Decimal(n).exp(context)到上下文指定的任何prec -- 你为什么认为不行呢?请查看http://svn.python.org/view/python/trunk/Lib/decimal.py?revision=77324&view=markup中使用的算法(2819-2892行)-- 在我看来似乎是正确的。 - Alex Martelli
显示剩余5条评论

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 )

嗯,最好有一些基本情况来终止递归!-) - Alex Martelli

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接