Kam*_*ely 67 floating-point precision matlab
我正在编写一个程序,我需要删除存储在矩阵中的重复点.问题在于,当检查这些点是否在矩阵中时,MATLAB不能在矩阵中识别它们,尽管它们存在.
在以下代码中,intersections函数获取交集点:
[points(:,1), points(:,2)] = intersections(...
obj.modifiedVGVertices(1,:), obj.modifiedVGVertices(2,:), ...
[vertex1(1) vertex2(1)], [vertex1(2) vertex2(2)]);
Run Code Online (Sandbox Code Playgroud)
结果:
>> points
points =
12.0000 15.0000
33.0000 24.0000
33.0000 24.0000
>> vertex1
vertex1 =
12
15
>> vertex2
vertex2 =
33
24
Run Code Online (Sandbox Code Playgroud)
应从结果中消除两点(vertex1和vertex2).它应该通过以下命令完成:
points = points((points(:,1) ~= vertex1(1)) | (points(:,2) ~= vertex1(2)), :);
points = points((points(:,1) ~= vertex2(1)) | (points(:,2) ~= vertex2(2)), :);
Run Code Online (Sandbox Code Playgroud)
在这之后,我们有了这个意想不到的结果:
>> points
points =
33.0000 24.0000
Run Code Online (Sandbox Code Playgroud)
结果应该是一个空矩阵.如你所见,第一对(或第二对)[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?
Run Code Online (Sandbox Code Playgroud)
问题是什么?
更令人惊讶的是,我制作了一个只有这些命令的新脚本:
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)), :);
Run Code Online (Sandbox Code Playgroud)
结果如预期:
>> points
points =
Empty matrix: 0-by-2
Run Code Online (Sandbox Code Playgroud)
gno*_*ice 93
您遇到的问题与计算机上如何表示浮点数有关.在我的答案结尾处出现了对浮点表示的更详细讨论("浮点表示"部分).的TL; DR版本:因为计算机具有有限数量的存储器,数字只能用有限精度表示.因此,浮点数的精度限制在一定的小数位数(双精度值约为16位有效数字,MATLAB中默认使用).
现在,以解决具体的示例中的问题...... 而24.0000与24.0000被显示在相同的方式,事实证明,他们实际上是在这种情况下非常小的小数金额不同.您没有看到它,因为MATLAB 默认只显示4位有效数字,保持整体显示整洁.如果要查看完整精度,则应发出format long命令或查看数字的十六进制表示形式:
>> pi
ans =
3.1416
>> format long
>> pi
ans =
3.141592653589793
>> num2hex(pi)
ans =
400921fb54442d18
Run Code Online (Sandbox Code Playgroud)
由于只能为浮点数表示有限数量的值,因此计算可能会产生一个落在其中两个表示之间的值.在这种情况下,结果必须四舍五入到其中一个.这引入了小的机器精度误差.这也意味着直接或通过某些计算初始化值可能会产生略微不同的结果.例如,该值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
Run Code Online (Sandbox Code Playgroud)
由于浮点值的差异非常小,因此任何比较都应通过检查值是否在彼此的某个范围(即容差)内来完成,而不是彼此完全相等.例如:
a = 24;
b = 24.000001;
tolerance = 0.001;
if abs(a-b) < tolerance, disp('Equal!'); end
Run Code Online (Sandbox Code Playgroud)
将显示"Equal!".
然后,您可以将代码更改为:
points = points((abs(points(:,1)-vertex1(1)) > tolerance) | ...
(abs(points(:,2)-vertex1(2)) > tolerance),:)
Run Code Online (Sandbox Code Playgroud)
浮点数(特别是浮点运算的IEEE 754标准)的一个很好的概述是David Goldberg 每个计算机科学家应该知道的关于浮点运算的内容.
二进制浮点数实际上由三个整数表示:符号位s,有效数(或系数/分数)b和指数e.对于双精度浮点格式,每个数字由内存中的64位表示,如下所示:
然后可以使用以下公式找到实际值:
该格式允许10 ^ -308到10 ^ 308范围内的数字表示.对于MATLAB你可以从这些限制realmin和realmax:
>> realmin
ans =
2.225073858507201e-308
>> realmax
ans =
1.797693134862316e+308
Run Code Online (Sandbox Code Playgroud)
由于存在用于表示浮点数的有限数量的比特,因此只有很多有限数可以在上述给定范围内表示.计算通常会导致一个值与这些有限表示中的一个不完全匹配,因此必须舍入值.这些机器精度误差使它们以不同的方式显现出来,如上面的例子中所讨论的.
为了更好地理解这些舍入误差,查看函数提供的相对浮点精度很有用eps,它可以量化从给定数字到下一个最大浮点表示的距离:
>> eps(1)
ans =
2.220446049250313e-16
>> eps(1000)
ans =
1.136868377216160e-13
Run Code Online (Sandbox Code Playgroud)
请注意,精度是相对于所表示的给定数字的大小; 较大的数字在浮点表示之间将具有较大的距离,因此在小数点之后具有较少的精度位数.这可能是一些计算的重要考虑因素.请考虑以下示例:
>> 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
Run Code Online (Sandbox Code Playgroud)
请注意,当我们将x范围的值移动[0 1]到范围时[10000 10001],计算平均值,然后减去平均偏移量进行比较,我们得到的值对于最后3位有效数字不同.这说明了数据的偏移或缩放如何改变对其执行的计算的准确性,这是某些问题必须考虑的因素.
Kit*_*YMG 13
类型
format long g
Run Code Online (Sandbox Code Playgroud)
此命令将显示该数字的FULL值.它可能像24.00000021321!= 24.00000123124
试着写
0.1 + 0.1 + 0.1 == 0.3.
警告:您可能对结果感到惊讶!