在我的程序中,十进制精度非常重要 我的很多计算必须精确到许多小数位(例如50)。
因为我正在使用python,所以我一直在使用十进制模块
(使用context()。prec = 99. ie; 设置为在实例化小数对象时具有99个小数位精度)
因为pythonic浮标不允许任何接近这样的准确度。
由于我希望用户指定计算精度的小数位,我必须在我的代码中实现几个round()函数。
不幸的是,内置的圆函数和小数对象不能很好地相互作用。
round(decimal.Decimal('2.000000000000000000001'),50)
# Number is 1e-21. There are 21 decimal places, much less than 50.
然而结果是 2.0 而不是 2.000000000000000000001
圆函数不会四舍五入到50.更不用了!
是的,我确保在Decimal对象的实例化时不会发生过度舍入,但是在调用后。 我总是将表示浮点数的字符串传递给Decimal构造函数,而不是pythonic浮点数。
为什么圆函数对我这样做?
(我意识到它可能最初设计用于pythonic浮点数,它永远不会有这么多的小数位,但文档声称Decimal对象完美地集成到python代码中并与内置的python函数兼容!)
非常感谢! (这让我非常不安,因为这个问题破坏了整个程序的使用)
规格:
python 2.7.1
Windows 7
十进制模块(内置)
答案 0 :(得分:39)
由于 round() 强制将其输入强制转换为常规二进制浮点数,因此使用 quantize() 方法舍入小数对象的首选方法是:< / p>
>>> from decimal import Decimal
>>> d = Decimal('2.000000000000000000001')
>>> d.quantize(Decimal(10) ** -20) # Round to twenty decimal places
Decimal('2.00000000000000000000')
要删除尾随零,请将 normalize() 应用于舍入结果:
>>> d = Decimal('2.000000000000000000001')
>>> d.quantize(Decimal(10) ** -20).normalize()
Decimal('2')
答案 1 :(得分:7)
问题尽可能地确定,round()
正在返回Python float
类型,而不是Decimal
类型。因此,您在decimal
模块上设置的精确度无关紧要,因为一旦您致电round()
,您就不再拥有Decimal
。
要解决此问题,您可能需要采用另一种方法来舍入不依赖round()
的数字。比如雷蒙德的建议。
您可能会发现这个简短的构思示例:http://ideone.com/xgPL9
答案 2 :(得分:4)
将round()
用于任何目的有困难:
(1)在Python 2.7中,round(Decimal('39 .142'))产生39.14,即浮点数; 3.2产生一个十进制。
>>> import decimal; round(decimal.Decimal('2.000000000000000000001'),50)
2.0 <<<=== ***float***
(2)round()只有一种舍入模式; Decimal.quantize
有很多。
(3)对于所有输入类型,单个舍入模式已更改:Python 2.7从0开始(在大多数业务应用程序中预期),而Python 3.2舍入到最接近的偶数倍10 ** - n(业务预期较少) )。
使用Decimal.quantize()
答案 3 :(得分:4)
尝试以下方法......
from decimal import Decimal, ROUND_HALF_UP, getcontext
getcontext().prec = 51
def round_as_decimal(num, decimal_places=2):
"""Round a number to a given precision and return as a Decimal
Arguments:
:param num: number
:type num: int, float, decimal, or str
:returns: Rounded Decimal
:rtype: decimal.Decimal
"""
precision = '1.{places}'.format(places='0' * decimal_places)
return Decimal(str(num)).quantize(Decimal(precision), rounding=ROUND_HALF_UP)
round_as_decimal('2.000000000000000000001', decimal_places=50)
希望有所帮助!
答案 4 :(得分:2)
如上所述,如果提供了Decimal,round()将返回一个float。 为了精确计算,我建议不要向下舍入十进制数,并且为了舍入最终结果,使用函数:
def dround(decimal_number, decimal_places):
return decimal_number.quantize(Decimal(10) ** -decimal_places)