我的目标是生成一个数字列表ls
,该列表从1.0
到1.499
结束,其中后续数字之间的步长为0.001.
最终,我正在加载一个文件,该文件具有一列浮点数,例如1.293, 1.101, ...
,所有浮点数后有3个数字,并希望查找从ls
中读取的每个数字的位置文件发生。
我创建ls
的两种方法:
ls = np.arange(1.,1.5,0.001)
和
ls = []
t = 1.0
dist = int((1.5-1.)/0.001)
for i in range(dist):
ls.append(t)
t+=0.001
根据1或2的方法,例如,希望以ls查找数字1.293
,但事实并非如此。例如,当我打印使用第二种方法创建的ls
时,它打印:[1.0, 1.001, 1.0019999999999998, 1.0029999999999997,...
而不是所需的[1.0, 1.001, 1.002, 1.003, ...].
另一方面,使用第一种方法创建ls
,并测试是否再次找到数字1.293
,如下所示:
for i in range(len(ls)):
print 'here ', i
if ls[i] == 1.293: print 'Found'
它从不打印“ Found”,这意味着它不包含数字1.293,根据构造,在使用np.arange
时,它将包含我给出的步长。
ls
,这样我才能真正获得1.0
和1.5
之间的所有数字,步长为0.001
,而不必处理更高的精度浮点数。 答案 0 :(得分:2)
浮点数不是精确的实数,而是可以放入52位二进制分数中的最接近的数。
例如,您不能将1.001
放入二进制分数;最接近的值为1.000999999999999889865875957184471189976
。如果将0.001
添加到该值,则与结果最接近的值为1.001999999999999779731751914368942379951
。但是最接近1.002
的值是1.002000000000000001776356839400250464678
。那些不相等。它们在2**52
中仅相差一个部分,但仍存在差异。
现在您将.001
加到一个比1.002
小一些的数字上,这样错误就会累积起来。最坏的情况是,您可能在2**52
中造成500倍的误差,因此总误差可能高达2**52
中500的误差,或者在2**43
中的1误差。 >
处理该问题的方法是永远不要检查两个浮点数是否相等;相反,请使用math.isclose
或np.isclose
来计算您的浮点数学运算会引入多少误差,并检查它们是否在该误差范围内。
在这种情况下,您只需要3位数的精度,并且可以确定最大误差永远不会接近这3位数,您可以简化内容并检查它们是否在{{{ 1}}。或者,甚至更简单地,您可以验证0.0001
使用的默认公差是否足够好,然后使用它们即可。
所以,代替这个:
isclose
…写下:
if ls[i] == 1.293:
另一种方法是使用浮点数十进制代替浮点数 binary 。
当然,它们也有相同的问题-1/3不能精确地适合小数部分,也不能完全适合二进制部分。但是,如果您要处理的唯一数字是小数,例如if math.isclose(ls[i], 1.293)
,那就没问题了。
而且,即使是 问题,能够选择精度而不是必须接受硬编码的精度,并以十进制数字而不是二进制数字进行选择,也会导致错误跟踪想起来容易得多。
唯一的问题是1/1000
值不是CPU的“本机”。十进制数学的运行速度大约慢了一个数量级,NumPy除了作为通用Python对象外,不知道如何处理十进制值,因此它无法为您提供通常的空间和速度节省等。但是,如果您仅处理500个号码,谁在乎?
所以:
decimal.Decimal
如果考虑到这一点,很容易将其简化为不需要所有这些from decimal import Decimal
ls = []
t = Decimal('1.0')
dist = int((Decimal('1.5')-Decimal('1.'))/Decimal('0.001'))
for i in range(dist):
ls.append(t)
t+=Decimal('0.001')
构造函数,因为许多数字只是纯整数:
Decimal('…')