Рассмотрим следующий код (Python 3.8.0 на MINGW64 в MSYS2 в Windows 10):
import numpy as np
from decimal import Decimal
aa = [25744, 25687, 25641, 25601, 25566, 25533, 25505, 25479, 25456, 25435]
npaa = np.array(aa)
print(np.mean(npaa)) # 25564.7
print(0.001*np.mean(npaa)) # 25.564700000000002
print( Decimal(np.mean(npaa)) ) # 25564.70000000000072759576141834259033203125
print( Decimal(0.001)*Decimal(np.mean(npaa)) ) # 25.56470000000000125976798437
Итак, среднее из приведенного выше списка целых чисел сначала печатается как 25564.7, чтоЯ ожидаю и хочу получить.
Но затем, как только я умножу это число на 0,0001, я получу тонну десятичных разрядов, вероятно, из-за точности float (im).
Итак,Я подумал - какого черта, я просто собираюсь использовать десятичный класс, тогда я должен получить «правильное» количество десятичных дробей в этом случае.
Но потом, как только я попробую Decimal(np.mean(npaa))
,Я получаю среднее значение в виде набора десятичных знаков: 25564.70000000000072759576141834259033203125
Так что, очевидно, np.mean(npaa)
уже содержит эти десятичные дроби - но по какой-то причине они просто не были напечатаны.
Так что этоДело в том, что, поскольку все, что у меня есть в списке, это целые числа, а в списке их 10, математически (в данном случае) невозможно получить какой-либо другой результат, кроме числа с 1 десятичным знаком и 1 только десятичным.
ТеперьЯ мог бы обойти это, напечатав среднее число в виде строки и отформатировав его как 1 десятичный, как в "{:.1f}".format(np.mean(npaa))
, а затем использовать эту строку в качестве источника десятичного числа - и это работает;но затем у меня есть другие массивы, длина которых не равна 10, и я хотел бы, чтобы минимальное количество десятичных знаков автоматически присутствовало в переменной - без необходимости вручную определять, какое количество десятичных знаков мне следует ожидать, а затем форматировать ихв виде строки.
Так что я могу просто попытаться использовать массив десятичных дробей (как пытался сделать связанный пост), что не совсем тривиально:
print( np.array(aa, dtype=Decimal) ) # [25744 25687 25641 25601 25566 25533 25505 25479 25456 25435]
print( np.array(aa).astype(Decimal) ) # [25744 25687 25641 25601 25566 25533 25505 25479 25456 25435]
print( np.array([Decimal(ax) for ax in aa]) ) # [Decimal('25744') Decimal('25687') Decimal('25641') Decimal('25601') Decimal('25566') Decimal('25533') Decimal('25505') Decimal('25479') Decimal('25456') Decimal('25435')]
print( np.mean( np.array([Decimal(ax) for ax in aa]) ) ) # 25564.7
print( type(np.mean( np.array([Decimal(ax) for ax in aa]) )) ) # <class 'decimal.Decimal'>
print( Decimal(0.001)*np.mean( np.array([Decimal(ax) for ax in aa]) ) ) # 25.56470000000000053217222296
... и все же, даже , если у меня теперь есть Decimal
25564,7 и Decimal
0,001, когда я их умножаю - в домене Decimal
! - Я все еще получаю 25.56470000000000053217222296!?
Как, черт возьми, я могу получить Python для вычисления 0,001 * 25564.7 как 25.5647, что и должно быть - без необходимости "кастовать", то естьвывести десятичное / плавающее значение в виде строки с ограниченным числом десятичных знаков? Разве десятичный класс не должен был это делать?
РЕДАКТИРОВАТЬ: Итак, я попробовал также подход sum()/len()
, как в связанном посте - сначала я подумал, что он это делает, но№:
print( sum(aa)/len(aa) ) # 25564.7
print( 0.001*sum(aa)/len(aa) ) # 25.5647
print( Decimal(0.001*sum(aa)/len(aa)) ) # 25.564699999999998425437297555617988109588623046875
print( sum(npaa)/len(npaa) ) # 25564.7
print( 0.001*sum(npaa)/len(npaa) ) # 25.5647
print( Decimal(0.001*sum(npaa)/len(npaa)) ) # 25.564699999999998425437297555617988109588623046875
https://docs.python.org/2/tutorial/floatingpoint.html
Между прочим, десятичный модуль также предоставляет хороший способ «увидеть» точное значение, которое хранится в любом конкретном Python-плавающем
https://docs.python.org/2/library/decimal.html
Десятичные числа могут быть представлены точно. Напротив, числа типа 1.1
и 2.2
не имеют точных представлений в двоичной форме с плавающей точкой. Конечные пользователи обычно не ожидают, что 1.1 + 2.2
будет отображаться как 3.3000000000000003
, как это происходит с двоичной плавающей точкой.
Итак, если Decimal
числа могут быть представлены точно, почему я получаюта же неточность с плавающей запятой, когда я использую класс Decimal
в этом контексте?