【问题标题】:Decimal precision in python without decimal module没有十进制模块的python中的十进制精度
【发布时间】:2012-10-23 19:11:17
【问题描述】:

我是 Python 的新手,想知道如何在不使用任何小数模块或浮点数的情况下控制任何给定数字的小数精度(例如:“%4f”%n)。

示例(编辑):

输入(2/7)

0.28571428571....

输入(1/3)

0.33333333333333....

并且我希望它们达到千位小数点或任何小数点。我正在考虑使用一段时间作为受控循环,但我不确定该怎么做。谢谢

编辑:我不使用十进制模块的原因只是为了让我可以概念化这些类型事物背后的算法/逻辑。只是想真正理解事物背后的逻辑。

【问题讨论】:

  • 为什么不能使用十进制模块?它是标准库的一部分
  • 您能否再填写您的示例?目前尚不清楚这些是输入还是输出,或者如果这些是输入,输出应该是什么样子。
  • 也不清楚:“千位小数”。你的意思是小数点后1000位吗?还是小数点后三位?
  • “概念化这类事物背后的算法/逻辑” - 所以你以前从未在纸上做过长除法?
  • 我不明白:首先你问如何“从概念上”做到这一点,然后你接受一个没有真正显示算法的答案,而是从内置无限精度小数到内置无限精度整数。这里哪里学? - 伙计们,不要误会我的意思,答案是简单中优雅的绝佳例子!我只是不清楚提问者如何在算法上有效地完成除法的成就,如果它必须逐步完成(暗示了一个循环)。

标签: python python-3.x


【解决方案1】:

我们可以使用long 来存储高精度的小数,并对其进行算术运算。打印出来的方法如下:

def print_decimal(val, prec):
    intp, fracp = divmod(val, 10**prec)
    print str(intp) + '.' + str(fracp).zfill(prec)

用法:

>>> prec = 1000
>>> a = 2 * 10**prec
>>> b = a//7
>>> print_decimal(b, prec)
0.2857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857

【讨论】:

    【解决方案2】:

    没有 Decimal 模块(为什么?),假设 Python 3:

    def divide(num, den, prec):
        a = (num*10**prec) // den
        s = str(a).zfill(prec+1)
        return s[0:-prec] + "." + s[-prec:]
    

    感谢@nneonneo 聪明的.zfill() 想法!

    >>> divide(2,7,1000)
    '0.28571428571428571428571428571428571428571428571428571428571428571428571428571
    42857142857142857142857142857142857142857142857142857142857142857142857142857142
    85714285714285714285714285714285714285714285714285714285714285714285714285714285
    71428571428571428571428571428571428571428571428571428571428571428571428571428571
    42857142857142857142857142857142857142857142857142857142857142857142857142857142
    85714285714285714285714285714285714285714285714285714285714285714285714285714285
    71428571428571428571428571428571428571428571428571428571428571428571428571428571
    42857142857142857142857142857142857142857142857142857142857142857142857142857142
    85714285714285714285714285714285714285714285714285714285714285714285714285714285
    71428571428571428571428571428571428571428571428571428571428571428571428571428571
    42857142857142857142857142857142857142857142857142857142857142857142857142857142
    85714285714285714285714285714285714285714285714285714285714285714285714285714285
    7142857142857142857142857142857142857142857'
    

    警告:这使用了楼层划分,所以divide(2,3,2) 会给你0.66 而不是0.67

    【讨论】:

    • 这看起来是个不错的方法,但小数位置仍需要一些工作(对于2/7,应该得到0.285... 而不是2.85...)。
    • @F.J.:是的,我刚刚意识到这一点。嗯,需要考虑一下,应该不会太难。
    • 我认为你应该使用str(b).zfill(prec+1) 来确保你有足够的零(例如,如果有人想打印 0.001)。那么你根本不需要使用if
    • 更好的方法也可能是使用ip, fp = divmod(b, 10**prec) 来获取整数位和小数位。然后就是print str(ip) + '.' + str(fp).zfill(prec)
    • @nneonneo:你应该把这个写成你自己的答案——这更聪明,我不可能把它归功于它:)
    【解决方案3】:

    虽然其他答案使用非常大的值来处理精度,但这实现了长除法。

    def divide(num, denom, prec=30, return_remainder=False):
        "long divison"
        remain=lim=0
        digits=[]
    
        #whole part
        for i in str(num):
            d=0;remain*=10
    
            remain+=int(i)
            while denom*d<=remain:d+=1
            if denom*d>remain:d-=1
    
            remain-=denom*d
            digits.append(d)
    
        #fractional part
        if remain:digits.append('.')
        while remain and lim<prec:
            d=0;remain*=10
    
            while denom*d<=remain:d+=1
            if denom*d>remain:d-=1
    
            remain-=denom*d
            digits.append(d)
            lim+=1
    
        #trim leading zeros        
        while digits[0]==0 and digits[1]!='.':
            digits=digits[1:]
    
        quotient = ''.join(list(map(str,digits)))
    
    
        if return_remainder:
            return (quotient, remain)
        else:
            return quotient
    

    因为它是除法算法,所以每个数字都是正确的,你可以得到余数(不像地板除法没有余数)。这里的精度我已经实现为小数点后的位数。

    >>> divide(2,7,70)
    '0.2857142857142857142857142857142857142857142857142857142857142857142857'
    >>> divide(2,7,70,True)
    ('0.2857142857142857142857142857142857142857142857142857142857142857142857', 1)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-20
      • 2016-12-19
      • 2016-01-31
      • 2015-11-26
      • 1970-01-01
      • 2014-08-14
      相关资源
      最近更新 更多