代码之家  ›  专栏  ›  技术社区  ›  qwr

Python Decimal类型精度错误

  •  2
  • qwr  · 技术社区  · 10 年前

    我有一个相当令人困惑的问题,我怀疑这与科学记数法和小数精度有关。以下是我的部分代码:

        def atan(x):
            # Calculate arctan(1/x)
            x = Decimal(x)
            current_value = Decimal(0)
            divisor = 1
            x_squared = x * x
            current_term = 1 / x
    
    
            while True:
                current_value += current_term
    
                divisor += 2
                current_term = (-current_term / x_squared) / divisor
                print(current_term)
    
                # The issue
                if current_term == Decimal(0):
                    break
    
            return current_value
    
        print(atan(5))
    

    这是基于公式 atan(1/x) = 1/x - 1/(3x^3) + 1/(5x^5) - ...

    然而,我发现 current_term 每一次循环迭代都会变小,其值将变为4E-80000。自从我设置了小数精度 getcontext().prec 到20,当前术语甚至不应支持这些值。我想不知怎么的 当前_时间 不是十进制类型,而是科学记数法/浮点类型,但python告诉它仍然是十进制类型。

    arctan(1/5)的正确值约为0.1973955。我得到的值是0.1973545,从第5位开始是错误的。即使我手动中断循环,由于某些原因,该值仍然是错误的。 如有任何解决此问题的帮助,我们将不胜感激。

    1 回复  |  直到 10 年前
        1
  •  3
  •   Raymond Hettinger    10 年前

    你的代码与公式不匹配。从下一个学期推断一个学期有点太难了;-)这个 1/(5x^5) 术语不是的倍数 1/(3x^3) 学期

    下面是直接为公式建模的代码:

    from decimal import Decimal
    
    def atan_recip(x):
        # Calculate arctan(1/x)
        x = Decimal(x)
    
        total = Decimal(0)
        sign = 1
        for i in range(1, 35, 2):
            total += sign / (i * x ** i)
            sign = -sign
            print(total)
    
    atan_recip(5)
    

    输出符合您的预期:

    0.2
    0.1973333333333333333333333333
    0.1973973333333333333333333333
    0.1973955047619047619047619047
    0.1973955616507936507936507936
    0.1973955597889754689754689754
    0.1973955598519908535908535908
    0.1973955598498063202575202575
    0.1973955598498834214339908457
    0.1973955598498806620234645299
    0.1973955598498807618878454823
    0.1973955598498807582406246127
    0.1973955598498807583748423407
    0.1973955598498807583698713137
    0.1973955598498807583700564416
    0.1973955598498807583700495142
    0.1973955598498807583700497745