Отбрасывать завершающие нули из десятичных

У меня длинный список Десятичных чисел и что я должен корректировать коэффициенты 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

ИЗМЕНИТЬ senderle fine answer заставил меня понять, что я иногда получаю число, подобное 250.0, которое при нормализации производит 2.5E + 2. Я думаю, в этих случаях я мог бы попытаться разобраться в них и преобразовать в int

Ответ 1

Вероятно, лучший способ сделать это, но вы можете использовать .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

Вы можете использовать метод 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

Или более компактно, используя quantize, как предложено user7116:

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

Вы также можете использовать to_integral(), как показано здесь, но я думаю, что использование 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')

Ответ 3

Ответа на этот вопрос 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')

Ответ 4

Ответ указан в 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')

Теперь все готово.

Ответ 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'

Ответ 6

Я закончил это:

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

note: литье возвращаемого значения в виде строки ограничит вас 12 значащими цифрами

Ответ 7

Это должно работать:

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

Ответ 8

Почему бы не использовать модули 10 из нескольких 10, чтобы проверить, есть ли остаток? Нет остатка означает, что вы можете заставить int()

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

x = 2/1
Выход: 2

x = 3/2
Выход: 1.5

Ответ 9

Я имел дело со значением из 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

Ответ 10

Слегка измененная версия A-IV ответа

ПРИМЕЧАНИЕ что 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