Десятичное число.Функция Decimal() выдает неупорядоченный результат

#python #python-3.x #floating-point #decimal #number-formatting

#python #python-3.x #с плавающей запятой #десятичный #форматирование чисел

Вопрос:

Я новичок в Python, и у меня возникли проблемы с десятичной функцией в модуле decimal в Python. Я понимаю, что из-за того, что Python хранит значения с плавающей запятой в памяти, чтобы выполнять вычисления над ними для получения удобочитаемого результата, мы можем либо использовать функцию round для нашего результата, либо использовать decimal .Функция Decimal() .

В приведенном ниже коде я создал класс calc1, который просто возвращает сложение и разность двух чисел. Тем не менее, всякий раз, когда я ее запускаю, даже если я включил decimal .Decimal() в моем коде результат продолжает быть неокругленным.

Код:

     import decimal as dec

    class calc1:
            'calc1 class is used for addition, subtraction only'
            obj_count = 0

            def __init__(self, value1, value2):
                    self.value1 = value1
                    self.value2 = value2
                    calc1.obj_count = calc1.obj_count   1

            def add(self):
                    return dec.Decimal(self.value1   self.value2)

            def sub(self):
                    return dec.Decimal(self.value1 - self.value2)

            def __str__(self):
                    return str(self.add())   " "   str(self.sub())

    obj_list = []

    for i in range(5):
            obj_list.append(calc1(3 * i, 5.6 * i))
            print(obj_list[i])
  

Вывод:

0.0 0
8.6 -2.5999999999999996447286321199499070644378662109375
17.2 -5.199999999999999289457264239899814128875732421875
25.799999999999997 -7.7999999999999971578290569595992565155029296875
34.4 -10.39999999999999857891452847979962825775146484375

Комментарии:

1. 5.6 является собственным значением с плавающей запятой до того, как оно достигнет decimal модуля, и 5.6 * i выполняет собственную операцию с плавающей запятой без использования decimal модуля. Я не часто использую Python и не использую decimal модуль, но я ожидаю, что вы захотите начать со "5.6" строки, преобразовать ее в decimal значение, а затем продолжить арифметику оттуда, полностью избегая родной Python с плавающей запятой.

Ответ №1:

Ваша проблема в том, что вы передаете значение, которое уже имеет точность с плавающей запятой, вашему классу и, в свою очередь Decimal , классу.

Вы можете избежать этого, просто передав Decimal строковое представление числа, которое вы хотите присвоить ему.

 from decimal import Decimal

class Calc1:
    def __init__(self, val_1, val_2):
        # these are now Decimal objects
        self.val_1 = val_1
        self.val_2 = val_2
    
    def add(self):
        # the Decimal conversion can be removed here
        # since both numbers are already Decimals
        return self.val_1   self.val_2

    def sub(self):
        return self.val_1 - self.val_2
   
    def __str__(self):
        return str(self.add())   " "   str(self.sub())

lst = []
for i in range(5):
    i_as_dec = Decimal(i)
    # Here we multiply a decimal representation of each of our numbers
    # this will hand a Decimal object to the Calc1 class
    lst.append(Calc1(Decimal('3') * i_as_dec, Decimal('5.6') * i_as_dec))
    print(lst[i])
  

Вывод:

 0.0 0.0
8.6 -2.6
17.2 -5.2
25.8 -7.8
34.4 -10.4
  

Комментарии:

1. Есть ли какой-нибудь способ преобразовать переменную с плавающей запятой в десятичную? Я попытался передать значение с плавающей запятой, преобразованное в строку, в Decimal(), и, похоже, оно все еще работает только половину времени. Я только что отредактировал 2 строки в своем исходном коде: self.value1 = dec.Decimal(str(value1)) self.value2 = dec.Decimal(str(value2)) и это не сработало

2. Как я уже упоминал в ответе, если вы передаете какое-либо значение в виде числа с плавающей запятой, оно уже имеет точность с плавающей запятой. Например, 5.6 * 3 в вашем интерпретаторе возвращает 16.799999999999997 . Передача этого значения в str() не изменит его каким-либо значимым образом перед преобразованием в строку. Ваш выбор — либо применить некоторый тип округления, либо начать с использования Decimal s в источнике, что и делает мой ответ.

Ответ №2:

Тем не менее, всякий раз, когда я ее запускаю, даже если я включил decimal .Decimal() в моем коде результат продолжает быть неокругленным.

Это соответствует тому, что decimal.Decimal должно выполняться в соответствии с его документами:

класс decimal .Decimal(value=»0″, context= None) Создает новый десятичный объект на основе value . (…) Если value является числом с плавающей запятой, двоичное значение с плавающей запятой преобразуется без потерь в его точный десятичный эквивалент. Для этого преобразования часто может потребоваться 53 или более цифр точности. Например, Decimal(float(‘1.1’)) преобразуется в Decimal(‘1.1000000000000088817841970012523233890533447265625’).

В качестве примечания decimal.Decimal — это класс, а не функция.

чтобы сгенерировать удобочитаемый результат, мы можем либо использовать функцию round для нашего результата, либо использовать decimal .Функция Decimal() .

Помимо этого вы можете решить отформатировать свой вывод, например, используя так называемые f-строки, например, если я хочу иметь 4 цифры после десятичной запятой:

 x = 0.1   0.1   0.1
print(x)  # 0.30000000000000004
print(f'{x:.4f}')  # 0.3000
  

Имейте в виду, что f-string доступны только в python3.6 и новее, и если вам нужно использовать более старую версию, рассмотрите возможность использования других методов форматирования.

Комментарии:

1. Есть ли какой-либо способ преобразовать значение с плавающей запятой в десятичное в терминах самой переменной, а не использовать f-строку или какой-либо другой инструмент форматирования для простого изменения печатного вывода?