Matlab双精度比较

6

我正在尝试将一个双精度浮点数数组与一个标量双精度浮点数进行相等性比较,但在某些情况下无法识别相等性。我怀疑这与双精度浮点数的表示方式有关(例如,1.0与1.00),但我无法弄清楚。

例如,我生成了一个由成千上万个双精度浮点数值组成的数组,在某个时间点上,其中最后几个值如下:

10.6000
-11.0000
10.2000
22.6000
3.4000

如果我使用命令array==10.2(或array=10.2000)测试等于10.2(或10.2000),则返回一个由0组成的数组。如果我手动将这些值放入数组中(例如,array=[10.6000 -11.0000 10.2000 22.6000 3.4000]),那么命令就会成功(即,array==10.2返回0 0 1 0 0)。请问为什么在程序上下文中生成数组时相等性会失败,而手动输入值时却成功?我可以通过使用近似而不是精确比较来纠正比较失败(例如,(array<10.20001) & (array>10.19999)),但这似乎并不令人满意。
编辑:数组中的值是通过迭代加或减一个常数双精度数(例如,0.2)生成的。因此,该数组对0.2取模应该处处相等于0。实际上,每个元素的模等于00.2,如下所示:
mod(array,0.2)
...
0.2000
     0
0.2000
0.2000
     0

如果手动将值放入数组并取模,那么所有0的预期值将得到。

3个回答

6
MATLAB在显示时会截断数组中的数字,只保留小数点后4位。也就是说,您的数组实际值可能是[10.600000000001,-10.99999999999,...]。您是正确的,这是由于计算机中浮点数的内部表示方式可能会导致计算中出现微小误差。

个人认为有两种解决方法,一种是像您所做的那样进行近似匹配,另一种是先将数组四舍五入(例如使用来自FileExchange的此工具),然后进行精确匹配。


非常有幫助。我的後續問題是,我的數字是通過在循環中添加或減去一個恆定的量(例如 0.2)來生成的,因此在進行模 0.2 (mod(array,0.2)) 時,數組中的數字在數學上應該等於 0。實際上,它們不是。它們等於 0 或 0.2。但當我手動輸入任何數組中的數字並將模 0.2 應用於它們時,會給出預期值 0。你能解釋這種行為嗎?謝謝! - user001
1
这涉及到计算机中浮点数的表示方式。一个众所周知的事实是计算机使用二进制而非十进制。然而,使用二进制会带来一个问题,即有限的小数如十进制中的0.2在二进制中无法用有限位数表示。也就是说,在计算机中,0.2的二进制表示实际上是0.001110011100111…等无穷尽的数字。然而,MATLAB使用64位来表示“Single”,这可能会导致2^(-65)的误差。这个误差非常微小,但当迭代次数很多时,它可能会累积。 - grapeot
精彩的解释。非常感谢你。 - user001
单精度浮点数需要64位吗?这个值是复数吗? - Ben Voigt

2

可能有些地方使用的是单精度,而另一些地方则使用双精度。例如,10.2的二进制表示在每种情况下都不同,因为它们在不同的位数后终止。因此它们是不同的:

>> if (single(10.2) == 10.2) disp('honk'); end
>> if (single(10.2) == single(10.2)) disp('honk'); end
honk

您需要在一些小差异中进行相等性检查:

 eps = 0.001;
 result = abs(array-10.2) < eps;

您可以使用whos命令查找数组中使用的精度:
>> whos A
  Name      Size            Bytes  Class     Attributes

  A         1x2                 8  single      

1
0.2 无法准确表示为二进制浮点数(请参见http://www.h-schmidt.net/FloatApplet/IEEE754.html),它是一个连分数0.1001 [1001 ...]。因此,将0.2添加到某些内容中可能不会完全达到您的预期。如果精确性很重要,请在问题的最小单位中进行操作,在这种情况下,最容易的方法可能是以10倍数工作,将2添加到数字,然后检查mod(num,2),最后除以10。 - Alex
非常感谢。通过加减0.25,问题得到了解决,这是有道理的,因为根据您提供的小程序,0.25可以被精确地表示为二进制浮点数。我想寻找更多信息的最佳途径可能是关于数字浮点表示的文章。 - user001
1
在我个人的谦虚意见中,一个更好的方法可能是修改你的算法以避免错误积累。这在数值计算中尤其值得注意。 - grapeot
1
是的,Alex的方法是一种“避免误差积累”的方法。通过适当的缩放,在整数字段中可以获得精确的结果,并且仅在最终除法步骤中引入误差(请注意,商不能用有限的二进制数字准确表示)。因此,您可以将误差限制在2^(-64)以下,这要好得多。 - grapeot
@grapeot:有没有一种方法可以显示Matlab double的全部64位?谢谢。 - user001
显示剩余4条评论

1
创建一个MATLAB函数文件,该文件将接受模数值(从3到9;即Z3到Z9),并输出由模数条件描述的最小可能值。
样本模拟:
Z = [3 4 5]; %模数Z3、Z4和Z5 r = [2 1 4]; %余数值 最小可能值为29。
Z输入必须是数组矩阵...您可以在其中键入从3到9的任何数字...您可以以任何顺序、任何配对或分组方式键入3、4、5、6、7、8、9...
r输入应与z输入数量相等...
输出应通过模数条件产生最小可能值...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接