如何在列表中查找浮点数?
我正在尝试从一个道路网络中创建一个点的列表。在这里,我想把这些点的坐标放在一个[x,y]的列表里,列表中的每个项都是浮点数格式。当我从网络中选择一个新点时,需要检查这个点是否已经在列表中。如果已经存在,就给这个网络特征分配相同的索引;如果不存在,就把新点添加到列表中,并给这个特征分配一个新的索引。
我知道浮点数的存储方式和整数不同,但对于完全相同的浮点数,我还是不能使用:
If new_point in list_of_points:
#do something
而应该使用:
for point in list_of_points:
if abs(point.x-new_point.x)<0.01 and abs(point.y-new_point.y)<0.01
#do something
这些点应该和我在ArcGIS软件中捕捉到的一模一样,当我在软件中检查坐标时,它们确实是完全相同的。
我问这个问题是因为:
1- 我觉得使用"in"可以让我的代码更整洁,也能提高速度,而用for循环在这种情况下显得有点笨重。
2- 我想知道:这是否意味着即使是完全相同的浮点数也会以不同的方式存储?
5 个回答
这个帖子虽然是旧的,但帮助我用列表推导式开发了自己的解决方案。因为当然,直接用 ==
来比较两个浮点数并不是个好主意。下面的代码会返回一个列表,里面是输入列表中所有与我们要找的值“差不多”的元素的索引。
def findFloats(listOfFloats, value):
return [i for i, number in enumerate(listOfFloats)
if abs(number-value) < 0.00001]
2: 完全相同的字面值(比如 "2.3")在特定的平台和数据类型下会以完全相同的浮点数形式存储,但一般来说,这还要看位数、字节序,以及可能使用的编译器。
为了确保在比较数字时的准确性,你至少应该把数字四舍五入到最不精确的那个数字的精度,或者(更好)像你这里做的那样处理。
>>> 1==1.00000000000000000000000000000000001
True
对于很多点来说,使用numpy会更快(而且可能看起来更优雅)。如果你把x和y坐标分开存成两个数组,分别叫做arrx和arry:
numpy.sometrue((arrx-point.x)**2+(arry-point.y)**2<tol**2)
如果某个点距离已有的点在tol范围内,这个代码会返回True。
任何一个Python的实现都应该以相同的、确定的、非随机的方式来存储一个浮点数。我认为你不可能输入同一个浮点数两次,然后它会以两种不同的方式存储。但是,我也不太相信在像ArcGIS这样的地理程序中,你会得到完全相同的坐标,特别是当分辨率非常小的时候。浮点数学有很多方式会让你的预期受到影响,所以你不应该指望得到完全相同的浮点数。而且在不同的机器和不同的版本之间,错误的可能性会更多。
如果你担心代码的优雅性,可以创建一个函数来简化for
循环。
def coord_in(coord, coord_list):
for other_coord in coord_list:
if abs(coord.x-other_coord.x)<0.00001 and abs(coord.y-other_coord.y)<0.00001:
return True
return False
比较两个浮点数是否相等通常不是个好主意。不过,有一些内置的函数可以用来进行这样的比较。在 numpy
库中,你可以使用 allclose
函数。比如说,
>>> np.allclose( (1.0,2.0), (1.00000001,2.0000001) )
True
这个函数会检查两个类似数组的输入,在一定的容忍度内是否逐个元素相等。你可以通过关键字参数来调整相对和绝对的容忍度。