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

标签 matlab floating-point precision

我正在编写一个程序,需要删除存储在矩阵中的重复点。问题在于,当检查这些点是否在矩阵中时,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


结果中应消除两个点(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


结果应该是一个空矩阵。如您所见,第一对(或第二对[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版本:由于计算机的内存量有限,因此数字只能以有限的精度表示。因此,浮点数的精度被限制为一定的小数位数(对于double-precision values,MATLAB中使用的默认值,大约16位有效数字)。

实际与显示精度

现在来解决问题中的特定示例... 24.000024.0000以相同的方式显示时,事实证明在这种情况下它们实际上相差很小的十进制数。您看不到它,因为MATLAB only displays 4 significant digits by default使整个显示保持整洁。如果要查看全精度,则应发出format long命令或查看数字的hexadecimal representation

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


初始化值与计算值

由于只能为浮点数表示有限数量的值,因此计算可能导致值介于这两种表示之间。在这种情况下,结果必须四舍五入到其中之一。这引入了一个小的machine-precision error。这也意味着直接初始化值或通过某种计算初始化值可能会产生稍微不同的结果。例如,值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(a-b) < tolerance, disp('Equal!'); end


将显示“等于!”。

然后,您可以将代码更改为:

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




浮点表示

David Goldberg很好地概述了浮点数(尤其是IEEE 754 standard for floating-point arithmetic)。

二进制浮点数实际上由三个整数表示:符号位s,有效位(或系数/分数)b和指数eWhat Every Computer Scientist Should Know About Floating-Point Arithmetic,每个数字由在内存中排列的64位表示,如下所示:

For double-precision floating-point format

然后可以通过以下公式找到实际值:

enter image description here

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

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


由于用于表示浮点数的位数有限,因此在上述给定范围内只能表示这么多的有限数。计算通常会得出与这些有限表示形式之一不完全匹配的值,因此必须对这些值进行四舍五入。如以上示例中所讨论的,这些realmax使自己以不同的方式显而易见。

为了更好地理解这些舍入误差,查看函数machine-precision errors提供的相对浮点精度很有用,该函数可量化从给定数到下一个最大浮点表示的距离:

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


注意,精度是相对于表示的给定数字的大小而言的。较大的数字将在浮点表示形式之间具有更大的距离,因此在小数点后的精度位数将减少。在进行某些计算时,这可能是一个重要的考虑因素。考虑以下示例:

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


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

关于matlab - 为什么在MATLAB中24.0000不等于24.0000?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43992701/

相关文章:

java - 从 Java 读取 .mat 文件

Matlab Codegen Eig 函数 - 这是一个错误吗?

c++ - 将浮点 vector 编码为十六进制或 base64binary 的最快方法

c++ - 为什么我的 C++ 程序从 long double 切换到 float128 时如此慢?

java - 由大元素和小元素组成的 float 组的总和

python - 以可变精度打印 float

matlab - 在 Matlab 中将颜色合并到图形表示中

string - Matlab:字符串不是真正的字符串?

c++ - 为什么我的 long long int 算术会以这种方式表现?

c++ - 什么时候是浮点运算 'invalid' ?