考虑以下代码(Windows 10上MSYS2中MINGW64上的Python 3.8.0):
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类,在这种情况下,我应该得到“正确的”小数位数。
但是,一旦我尝试Decimal(np.mean(npaa))
,我就会得到一小数的平均值:25564.70000000000072759576141834259033203125
显然,np.mean(npaa)
已经包含了这些小数-但由于某些原因,它们没有被打印。
这就是问题-因为列表中我所有的都是整数,并且列表中有10个整数,在数学上(在这种情况下)我不可能得到任何其他结果,只有一个小数点后一位的数字,和仅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
...,但是 even ,如果我现在有Decimal
为25564.7,乘以Decimal
为0.001(在Decimal
域中) ! -我 still 得到25.56470000000000053217222296!?
我该如何让Python将0.001 * 25564.7计算为25.5647,这就是应该的样子-无需“强制转换”,即将十进制/浮点值打印为字符串,并带有有限的小数位数? Decimal类是否应该能够做到这一点?
编辑:所以,我也尝试了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
类时却得到相同的浮点不精确度?
答案 0 :(得分:0)
好的,我要把这个作为答案发布-感谢@ user2357112的评论,现在我知道,如果我抛出/投射,无论首先如何打印浮点数(可能是四舍五入的)浮动到Decimal
中,我仍然会遇到相同的舍入错误。因此,我要么必须从一开始就在整数级别上工作,要么在字符串级别上工作。
因此,在这种特殊情况下(数组中的ins,寻找均值),我可以这样做:
tmean = Decimal(int(sum(npaa)))/Decimal(len(npaa))
print( type(tmean), tmean ) # <class 'decimal.Decimal'> 25564.7
因此,我基本上首先运行了数组的总和,结果得到一个整数,并将其强制转换为Decimal
。请注意,我首先必须将总和转换为Python内置的int
,否则:
Decimal(sum(npaa))/Decimal(len(npaa)) # TypeError: conversion from numpy.int32 to Decimal is not supported
事实证明,将整个numpy数组“投射”到内置的Python int
:create and use NumPy array with dtype of builtin int中是非常困难的,因此剩下的唯一事情就是将总和转换为单个数字,内置到int
中。
但是一旦完成,我就将平均值计算除以两个Decimal
类整数-在这种情况下,我可以合理地期望最终计算中的小数位数正确(在这种情况下为一个)的平均值。
编辑:最后,如果我想计算该平均时间0.001,我需要将其用作Decimal('0.001')*tmean
中的字符串以获取正确的小数位数-如果我只使用{{1} }与float参数一起使用时,floc不精确性本来就已经流行起来,仅使用Decimal(0.001)
类就无济于事了。