为什么在MATLAB中24.0000不等于24.0000?

我正在写一个程序,我需要删除存储在matrix中的重复点。 问题是,当检查这些点是否在matrix中时,MATLAB虽然存在,但在matrix中不能识别它们。

在下面的代码中, 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 

应该从结果中删除两个点( vertex1vertex2 )。 它应该由以下命令完成:

 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 

结果应该是一个空matrix。 如你所见,第一个(或第二个?)对[33.0000 24.0000]已被淘汰,但不是第二个。

然后我检查了这两个expression式:

 >> 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 

您遇到的问题涉及如何在计算机上表示浮点数字 。 浮点表示的更详细的讨论出现在我的答案的末尾(“浮点表示”部分)。 TL; DR版本:因为计算机具有有限数量的内存,数字只能以有限的精度表示。 因此,浮点数的精度被限制在一定数量的小数位( 双精度值约为16位有效数字,在MATLAB中默认使用)。

实际与显示精度

现在要解决问题中的具体示例… 24.000024.0000以相同的方式显示 ,事实certificate,在这种情况下它们实际上相差很小的小数。 你看不到它,因为MATLAB 默认只显示4位有效数字 ,保持整体显示整齐。 如果你想看到完整的精度,你应该发出format long命令或查看数字的hex表示 :

 >> pi ans = 3.1416 >> format long >> pi ans = 3.141592653589793 >> num2hex(pi) ans = 400921fb54442d18 

初始化值与计算值

由于浮点数只能表示有限数量的值,因此计算可能会导致落在这两个表示之间的值。 在这种情况下,结果必须四舍五入到其中之一。 这引入了一个小的机器精度错误 。 这也意味着直接初始化一个值或者通过一些计算可以给出稍微不同的结果。 例如, 0.1的值没有精确的浮点表示(也就是稍微四舍五入),所以最终会出现像这样的反直觉结果,这是由于四舍五入误差累积的结果:

 >> a=sum([0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1]); % Sum 10 0.1s >> b=1; % Initialize to 1 >> a == b ans = logical 0 % They are unequal! >> num2hex(a) % Let's check their hex representation to confirm ans = 3fefffffffffffff >> num2hex(b) ans = 3ff0000000000000 

如何正确处理浮点比较

由于浮点值可能相差很小,所以应该通过检查这些值是否在彼此的某个范围(即容差)之内来完成比较,而不是完全相等。 例如:

 a = 24; b = 24.000001; tolerance = 0.001; if abs(ab) < tolerance, disp('Equal!'); end 

将显示“等于!”。

然后,您可以将您的代码更改为如下所示:

 points = points((abs(points(:,1)-vertex1(1)) > tolerance) | ... (abs(points(:,2)-vertex1(2)) > tolerance),:) 

浮点表示

浮点数(特别是浮点运算的IEEE 754标准 )的一个很好的概述是每个计算机科学家应该知道的关于浮点运算的David Goldberg。

二进制浮点数实际上由三个整数表示:符号位s ,有效数(或系数/分数) b和指数e 。 对于双精度浮点格式 ,每个数字由内存中的64位表示,如下所示:

在这里输入图像描述

然后可以用下面的公式find真正的价值:

在这里输入图像描述

这种格式允许在10 ^ -308到10 ^ 308范围内的数字表示。 对于MATLAB,您可以从realminrealmax获得这些限制:

 >> realmin ans = 2.225073858507201e-308 >> realmax ans = 1.797693134862316e+308 

由于用于表示浮点数的位数是有限的,因此在上述给定范围内只能表示如此多的有限数。 计算结果通常会导致与这些有限表示之一不完全匹配的值,所以值必须四舍五入。 正如上面的例子所讨论的,这些机器精度错误使得它们以不同的方式变得明显。

为了更好地理解这些舍入错误,查看由函数eps提供的相对浮点精度是有用的,该函数eps量化从给定数字到下一个最大浮点表示的距离:

 >> eps(1) ans = 2.220446049250313e-16 >> eps(1000) ans = 1.136868377216160e-13 

请注意,精度与所表示的给定数量的大小有关; 较大的数字将在浮点表示之间具有较大的距离,并且因此在小数点之后将具有较less的精度位数。 有些计算可能是一个重要的考虑因素。 考虑下面的例子:

 >> format long % Display full precision >> x = rand(1, 10); % Get 10 random values between 0 and 1 >> a = mean(x) % Take the mean a = 0.587307428244141 >> b = mean(x+10000)-10000 % Take the mean at a different scale, then shift back b = 0.587307428244458 

请注意,当我们将x的值从范围[0 1]到范围[10000 10001] ,计算平均值,然后减去平均偏移量进行比较,我们得到一个最后3位有效数字不同的值。 这说明了数据的偏移或缩放如何改变对其执行的计算的准确性,这是必须考虑的问题。

看这篇文章: 浮点的危险 。 虽然它的例子在FORTRAN中,但它对于几乎所有的现代编程语言都是有意义的,包括MATLAB。 您的问题(及其解决方法)在“安全比较”一节中介绍。

types

 format long g 

该命令将显示数字的FULL值。 这很可能是24.00000021321!= 24.00000123124

尝试写作

0.1 + 0.1 + 0.1 == 0.3。

警告:您可能会对结果感到惊讶!

也许这两个数字真的是24.0和24.000000001,但你没有看到所有的小数位。

检查出Matlab的EPS函数http://matlab.izmiran.ru/help/techdoc/ref/eps.html

Matlab使用精度高达16位的浮点运算(仅显示5个数字)。