Почему я должен прибегать к строкам, чтобы получить точную обработку числа
При преобразовании данных в decimal
Иногда я получаю неверные результаты:
from decimal import *
D = Decimal
>>> D(5.2).quantize(D('.00000'), rounding=ROUND_DOWN)
Decimal('5.20000')
>>> D(5.3).quantize(D('.00000'), rounding=ROUND_DOWN)
Decimal('5.29999')
Я не думаю, что неточность с плавающей запятой является оправданием, поскольку я использую специализированный класс для работы с числами! Цитируется из документации по питону:
Десятичное число "основано на модели с плавающей запятой, которая была разработана с учетом потребностей людей и обязательно имеет первостепенный руководящий принцип - компьютеры должны обеспечивать арифметику, которая работает так же, как арифметика, которую люди изучают в школе". - выдержка из десятичная арифметическая спецификация
Это работает:
x=round(x - .0000049,5)
D(str(x) + (5-len(str(x).split('.')[1]))*'0')
2 ответа
Так как 5.3
само по себе уже неправильно. Когда вы передаете это Decimal()
, это не будет волшебно исправить это. Вы должны использовать Decimal()
на каждом шагу с самого начала. Это значит писать Decimal('5.3')
вместо Decimal(5.3)
,
РЕДАКТИРОВАТЬ: OP заявил, что они используют JSON. Вот как вы анализируете десятичные числа из JSON:
import json, decimal
decimal_decoder = json.JSONDecoder(parse_float=decimal.Decimal)
parsed_json = decimal_decoder.decode(raw_json)
(где raw_json
это JSON как строка). Это даст правильные десятичные числа.
Ваши предположения неверны. Литерал 5.3 недействителен (как уже сказал Кевин).
Проблема здесь в том, что вы не можете начать с неверного представления (с плавающей точкой), а затем предположить, что волшебство произойдет, и все исправить.
Легко построить нормальную среду:
a = D(53)
b = D(10)
c = a/b
А потом c
является действительным номером.
Проблема в том, откуда берется ваше десятичное число? Если у вас есть 5.3 и вы хотите правильное представление, вы спрашиваете правильное представление числа, которое у вас есть в виде строки. Затем вам нужно использовать строку. Если у вас есть подразделение, воспользуйтесь этим и выполните операцию в decimal.Decimal
среда. Если пользователь передал число, оставьте его в виде строки, а затем преобразуйте его в десятичное и т. Д.
Бонус редактировать: помните, что
$ 5.2999999999999999 == 5.3
> True
Вот что означает, что "буквальное представление неверно" (с вашей точки зрения и ограничений). С помощью 5.3
как поплавок подразумевает эту проблему.