drop trailing zeros from decimal

前端 未结 9 1891
庸人自扰
庸人自扰 2020-11-29 03:54

I have a long list of Decimals and that I have to adjust by factors of 10, 100, 1000,..... 1000000 depending on certain conditions. When I multiply them there is sometimes

相关标签:
9条回答
  • 2020-11-29 04:12

    Answer from the Decimal FAQ in the documentation:

    >>> def remove_exponent(d):
    ...     return d.quantize(Decimal(1)) if d == d.to_integral() else d.normalize()
    
    >>> remove_exponent(Decimal('5.00'))
    Decimal('5')
    
    >>> remove_exponent(Decimal('5.500'))
    Decimal('5.5')
    
    >>> remove_exponent(Decimal('5E+3'))
    Decimal('5000')
    
    0 讨论(0)
  • 2020-11-29 04:17

    Answer is mentioned in FAQ (https://docs.python.org/2/library/decimal.html#decimal-faq) but does not explain things.

    To drop trailing zeros for fraction part you should use normalize:

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

    But this works different for numbers with leading zeros in sharp part:

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

    In this case we should use `to_integral':

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

    So we could check if there's a fraction part:

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

    And use appropriate method then:

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

    Try it:

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

    Now we're done.

    0 讨论(0)
  • 2020-11-29 04:18

    There's probably a better way of doing this, but you could use .rstrip('0').rstrip('.') to achieve the result that you want.

    Using your numbers as an example:

    >>> 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
    

    And here's the fix for the problem that gerrit pointed out in the comments:

    >>> s = str(Decimal('1500'))
    >>> print s.rstrip('0').rstrip('.') if '.' in s else s
    1500
    
    0 讨论(0)
  • 2020-11-29 04:22

    Use the format specifier %g. It seems remove to trailing zeros.

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

    It also works without the Decimal function

    >>> "%g" % (2.5 * 10)
    '25'
    >>> "%g" % (2.5678 * 1000)
    '2567.8'
    
    0 讨论(0)
  • 2020-11-29 04:23

    This should work:

    '{:f}'.format(decimal.Decimal('2.5') * 10).rstrip('0').rstrip('.')
    
    0 讨论(0)
  • 2020-11-29 04:28

    Slightly modified version of A-IV's answer

    NOTE that Decimal('0.99999999999999999999999999995').normalize() will round to 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
    
    
    0 讨论(0)
提交回复
热议问题