我正在编写一个程序,需要删除矩阵中存储的重复点。问题是,当检查这些点是否在矩阵中时,MATLAB无法识别矩阵中的这些点,尽管它们存在
在以下代码中,intersections
函数获取交点:
[points(:,1), points(:,2)] = intersections(...
obj.modifiedVGVertices(1,:), obj.modifiedVGVertices(2,:), ...
[vertex1(1) vertex2(1)], [vertex1(2) vertex2(2)]);
结果是:
>> points
points =
12.0000 15.0000
33.0000 24.0000
33.0000 24.0000
>> vertex1
vertex1 =
12
15
>> vertex2
vertex2 =
33
24
应从结果中删除两点(vertex1
和vertex2
)。应通过以下命令执行此操作:
points = points((points(:,1) ~= vertex1(1)) | (points(:,2) ~= vertex1(2)), :);
points = points((points(:,1) ~= vertex2(1)) | (points(:,2) ~= vertex2(2)), :);
在这样做之后,我们得到了一个意想不到的结果:
>> points
points =
33.0000 24.0000
结果应该是一个空矩阵。如您所见,第一(或第二?)对[33.0000 24.0000]
已被消除,但第二对未被消除
然后我检查了这两个表达式:
>> points(1) ~= vertex2(1)
ans =
0
>> points(2) ~= vertex2(2)
ans =
1 % <-- It means 24.0000 is not equal to 24.0000?
有什么问题
更令人惊讶的是,我制作了一个新脚本,其中只有以下命令:
points = [12.0000 15.0000
33.0000 24.0000
33.0000 24.0000];
vertex1 = [12 ; 15];
vertex2 = [33 ; 24];
points = points((points(:,1) ~= vertex1(1)) | (points(:,2) ~= vertex1(2)), :);
points = points((points(:,1) ~= vertex2(1)) | (points(:,2) ~= vertex2(2)), :);
结果如预期:
>> points
points =
Empty matrix: 0-by-2
您遇到的问题与floating-point numbers在计算机上的表示方式有关。关于浮点表示法的更详细讨论出现在我的答案的末尾(“浮点表示法”部分)。TL;DR版本:由于计算机内存有限,数字只能以有限的精度表示。因此,浮点数的精度被限制在一定的小数位数(大约16位有效数字表示double-precision values,这是MATLAB中使用的默认值)
实际精度与显示精度
现在来解决问题中的具体例子虽然
24.0000
和24.0000
以相同的方式显示,,但在这种情况下,它们的差异实际上非常小。您看不到它,因为MATLAB only displays 4 significant digits by default保持了整体显示的整洁。如果您想看到完整的精度,您应该发出format long
命令或查看hexadecimal representation的数字:初始化值与计算值
由于浮点数只能表示有限数量的值,因此计算结果可能介于这两种表示之间。在这种情况下,结果必须四舍五入到其中一个。这引入了一个小的machine-precision error。这也意味着直接初始化一个值或通过某些计算初始化一个值可以得到稍微不同的结果。例如,值
0.1
没有精确的浮点表示法(即,它会稍微四舍五入),因此由于四舍五入错误的累积方式,最终会出现这样的反直觉结果:如何正确处理浮点比较
由于浮点值之间的差异可能非常小,因此任何比较都应通过检查值是否在彼此的某个范围(即公差)内(而不是完全相等)来完成。例如:
将显示“相等!”
然后,您可以将代码更改为:
浮点表示法
David Goldberg的What Every Computer Scientist Should Know About Floating-Point Arithmetic对浮点数(特别是IEEE 754 standard for floating-point arithmetic)有一个很好的概述
二进制浮点数实际上由三个整数表示:符号位
s
、有效位(或系数/分数)b
和指数e
For double-precision floating-point format,每个数字由内存中的64位表示,如下所示:然后可通过以下公式找到实际值:
此格式允许在10^-308到10^-308范围内表示数字。对于MATLAB,您可以从^{} 和^{} 获得这些限制:
由于用于表示浮点数的位数是有限的,因此在上述给定范围内只能表示这么多的有限位数。计算通常会导致一个值与这些有限表示形式中的一个不完全匹配,因此这些值必须舍入。这些{a13}以不同的方式表现出来,如上述示例所述
为了更好地理解这些舍入错误,有必要查看函数^{} 提供的相对浮点精度,该函数量化从给定数字到下一个最大浮点表示的距离:
请注意,精度与所表示的给定数字的大小有关;数字越大,浮点表示之间的距离越大,因此小数点后的精度位数越少。这在一些计算中可能是一个重要的考虑因素。考虑下面的例子:
请注意,当我们将
x
的值从范围[0 1]
移动到范围[10000 10001]
时,计算平均值,然后减去用于比较的平均偏移量,我们得到一个与最后3个有效数字不同的值。这说明了数据的偏移或缩放如何改变对其执行的计算的准确性,这是必须考虑到某些问题的类型
此命令将显示数字的完整值。可能是24.00000021321!=24.00000123124
看看这篇文章:The Perils of Floating Point。虽然它的例子是用FORTRAN编写的,但它对几乎所有现代编程语言都有意义,包括MATLAB。您的问题(及其解决方案)在“安全比较”部分中进行了描述
相关问题 更多 >
编程相关推荐