舍入小数的问题(python)

Ant*_*rth 22 python decimal rounding

在我的程序中,十进制精度非常重要.
我的很多计算必须精确到许多小数位(例如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.
Run Code Online (Sandbox Code Playgroud)

然而结果是2.0而不是2.000000000000000000001
圆函数没有四舍五入到50.更少!

是的,我已经确保在Decimal对象的实例化时不会发生过度舍入,但是在调用round之后.
我总是将表示浮点数的字符串传递给Decimal构造函数,而不是pythonic浮点数.

为什么圆函数对我这样做?
(我意识到它可能最初设计用于pythonic浮点数,它永远不会有这么多的小数位,但是文档声称Decimal对象完美地集成到python代码中并且与内置的python函数兼容!)

非常感谢!
(这让我非常不安,因为这个问题破坏了整个程序的使用)

规格:
python 2.7.1
Windows 7
十进制模块(内置)

Ray*_*ger 40

由于round()将其输入强制转换为常规二进制浮点数,因此舍入小数对象的首选方法是使用quantize()方法:

>>> from decimal import Decimal
>>> d = Decimal('2.000000000000000000001')

>>> d.quantize(Decimal(10) ** -20)     # Round to twenty decimal places
Decimal('2.00000000000000000000')
Run Code Online (Sandbox Code Playgroud)

要删除尾随零,请将normalize()应用于舍入结果:

>>> d = Decimal('2.000000000000000000001')
>>> d.quantize(Decimal(10) ** -20).normalize()
Decimal('2')
Run Code Online (Sandbox Code Playgroud)

  • 使用字符串格式来控制小数的外观: ``format(Decimal('2.00000000000000000000'), '.1f')`` 打印到一位小数。您也可以将其转换为字符串并使用 *rstrip*:``str(Decimal('2.000000000000000000000')).rstrip('0')``。 (2认同)

aro*_*oth 7

问题,就像我可以确定的那样,round()是返回Python float类型,而不是Decimal类型.因此,在decimal模块上设置的精度无关紧要,因为一旦你打电话给round()你就不再有了Decimal.

要解决这个问题,你可能不得不想出一种替代方法来舍入你不依赖的数字round().比如雷蒙德的建议.

您可能会发现这个简短的构思示例:http://ideone.com/xgPL9


kam*_*ill 5

尝试以下...

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)
Run Code Online (Sandbox Code Playgroud)

希望有帮助!