从十进制中删除尾随零

时间:2012-06-27 13:42:10

标签: python decimal

我有很长的小数列表,我必须根据某些条件调整因子10,100,1000,..... 1000000。当我乘以它们时,有时候我想摆脱无用的尾随零(虽然并不总是)。例如......

from decimal import Decimal

# outputs 25.0,  PROBLEM!  I would like it to output 25
print Decimal('2.5') * 10

# outputs 2567.8000, PROBLEM!  I would like it to output 2567.8
print Decimal('2.5678') * 1000

是否有一个函数告诉小数对象丢弃这些无关紧要的零?我能想到这样做的唯一方法是转换为字符串并使用正则表达式替换它们。

应该提一下我使用的是python 2.6.5

EDIT senderle的好答案让我意识到我偶尔得到一个像250.0这样的数字,当归一化时产生2.5E + 2。我想在这些情况下我可以尝试将它们排序并转换为int

11 个答案:

答案 0 :(得分:85)

您可以使用normalize方法删除额外的精确度。

>>> print decimal.Decimal('5.500')
5.500
>>> print decimal.Decimal('5.500').normalize()
5.5

为避免在小数点左侧剥离零,可以这样做:

def normalize_fraction(d):
    normalized = d.normalize()
    sign, digits, exponent = normalized.as_tuple()
    if exponent > 0:
        return decimal.Decimal((sign, digits + (0,) * exponent, 0))
    else:
        return normalized

或者更紧凑,使用user7116建议的quantize

def normalize_fraction(d):
    normalized = d.normalize()
    sign, digit, exponent = normalized.as_tuple()
    return normalized if exponent <= 0 else normalized.quantize(1)

您也可以使用to_integral() here,但我认为使用as_tuple这种方式更具有自我记录功能。

我在几个案例中测试了这些;如果您发现不起作用,请发表评论。

>>> normalize_fraction(decimal.Decimal('55.5'))
Decimal('55.5')
>>> normalize_fraction(decimal.Decimal('55.500'))
Decimal('55.5')
>>> normalize_fraction(decimal.Decimal('55500'))
Decimal('55500')
>>> normalize_fraction(decimal.Decimal('555E2'))
Decimal('55500')

答案 1 :(得分:33)

可能有更好的方法,但您可以使用.rstrip('0').rstrip('.')来达到您想要的结果。

以您的数字为例:

>>> s = str(Decimal('2.5') * 10)
>>> print s.rstrip('0').rstrip('.') if '.' in s else s
25
>>> s = str(Decimal('2.5678') * 1000)
>>> print s.rstrip('0').rstrip('.') if '.' in s else s
2567.8

这是针对gerrit在评论中指出的问题的解决方法:

>>> s = str(Decimal('1500'))
>>> print s.rstrip('0').rstrip('.') if '.' in s else s
1500

答案 2 :(得分:27)

来自http://docs.python.org/2/library/decimal.html#decimal-faq

的回答
>>> def remove_exponent(d):
...    return d.quantize(Decimal(1)) if d == d.to_integral() else d.normalize()

>>> remove_exponent(Decimal('5.500'))
Decimal('5.5')

>>> remove_exponent(Decimal('5E+3'))
Decimal('5000')

答案 3 :(得分:11)

答案在FAQ(https://docs.python.org/2/library/decimal.html#decimal-faq)中提到,但没有解释。

要删除小数部分的尾随零,您应该使用normalize

>>> Decimal('100.2000').normalize()
Decimal('100.2')
>> Decimal('0.2000').normalize()
Decimal('0.2')

但是对于尖锐部分中带有前导零的数字,这种情况有所不同:

>>> Decimal('100.0000').normalize()
Decimal('1E+2')

在这种情况下,我们应该使用`to_integral':

>>> Decimal('100.000').to_integral()
Decimal('100')

所以我们可以检查是否有一小部分:

>>> Decimal('100.2000') == Decimal('100.2000').to_integral()
False
>>> Decimal('100.0000') == Decimal('100.0000').to_integral()
True

然后使用适当的方法:

def remove_exponent(num):
    return num.to_integral() if num == num.to_integral() else num.normalize()

试一试:

>>> remove_exponent(Decimal('100.2000'))
Decimal('100.2')
>>> remove_exponent(Decimal('100.0000'))
Decimal('100')
>>> remove_exponent(Decimal('0.2000'))
Decimal('0.2')

现在我们已经完成了。

答案 4 :(得分:5)

使用格式说明符%g。似乎删除了尾随零。

>>> "%g" % (Decimal('2.5') * 10)
'25'
>>> "%g" % (Decimal('2.5678') * 1000)
'2567.8'

没有Decimal功能

也可以
>>> "%g" % (2.5 * 10)
'25'
>>> "%g" % (2.5678 * 1000)
'2567.8'

答案 5 :(得分:1)

我最终这样做了:

import decimal

def dropzeros(number):
    mynum = decimal.Decimal(number).normalize()
    # e.g 22000 --> Decimal('2.2E+4')
    return mynum.__trunc__() if not mynum % 1 else float(mynum)

print dropzeros(22000.000)
22000
print dropzeros(2567.8000)
2567.8

注意:将返回值转换为字符串会将您限制为12位有效数字

答案 6 :(得分:0)

这应该有效:

'{:f}'.format(decimal.Decimal('2.5') * 10).rstrip('0').rstrip('.')

答案 7 :(得分:0)

为什么不使用10的倍数的模块10来检查是否有余数?没有余数意味着你可以强制int()

if (x * 10) % 10 == 0:
    x = int(x)

x = 2/1
输出:2

x = 3/2
输出:1.5

答案 8 :(得分:0)

我正在处理来自json字典的值(由API返回)。以上所有都没有帮助我所以我通过自己的帮助函数构建。它会截断所有尾随零。

我希望它可以帮助那里的人

def remove_zeros(num):
    nums = list(num)
    indexes = (list(reversed(range(len(nums)))))
    for i in indexes:
        if nums[i] == '0':
            del nums[-1]
        else:
            break
    return "".join(nums)

num = "0.000000363000"
print(remove_zeros(num))

打印:

0.000000363

答案 9 :(得分:0)

A-IV's answer的稍加修改的版本

注意Decimal('0.99999999999999999999999999995').normalize()将舍入到Decimal('1')

def trailing(s: str, char="0"):
    return len(s) - len(s.rstrip(char))

def decimal_to_str(value: decimal.Decimal):
    """Convert decimal to str

    * Uses exponential notation when there are more than 4 trailing zeros
    * Handles decimal.InvalidOperation
    """
    # to_integral_value() removes decimals
    if value == value.to_integral_value():
        try:
            value = value.quantize(decimal.Decimal(1))
        except decimal.InvalidOperation:
            pass
        uncast = str(value)
        # use exponential notation if there are more that 4 zeros
        return str(value.normalize()) if trailing(uncast) > 4 else uncast
    else:
        # normalize values with decimal places
        return str(value.normalize())
        # or str(value).rstrip('0') if rounding edgecases are a concern

答案 10 :(得分:0)

为了展示不同的可能性,我使用了 to_tuple() 来实现相同的结果。

def my_normalize(dec):
    """
    >>> my_normalize(Decimal("12.500"))
    Decimal('12.5')
    >>> my_normalize(Decimal("-0.12500"))
    Decimal('-0.125')
    >>> my_normalize(Decimal("0.125"))
    Decimal('0.125')
    >>> my_normalize(Decimal("0.00125"))
    Decimal('0.00125')
    >>> my_normalize(Decimal("125.00"))
    Decimal('125')
    >>> my_normalize(Decimal("12500"))
    Decimal('12500')
    >>> my_normalize(Decimal("0.000"))
    Decimal('0')
    """
    if dec is None:
        return None

    sign, digs, exp = dec.as_tuple()
    for i in list(reversed(digs)):
        if exp >= 0 or i != 0:
            break
        exp += 1
        digs = digs[:-1]

    if not digs and exp < 0:
        exp = 0

    return Decimal((sign, digs, exp))