mod()操作奇怪的行为

时间:2014-03-19 23:57:59

标签: matlab

我使用mod()比较数字的0.01位是否为2。

if mod(5.02*100, 10) == 2 
...
end

结果是mod(5.02*100, 10) = 2返回0;

但是,如果我使用mod(1.02*100, 10) = 2mod(20.02*100, 10) = 2,则会返回1.

mod(5.02*100, 10) - 2的结果是

ans =

  -5.6843e-14

这可能是matlab的错误吗?

我使用的版本是R2013a。版本8.1.0

2 个答案:

答案 0 :(得分:4)

要正确使用mod()来测试数字的特定数字,请使用round()将其四舍五入到最接近的整数并补偿浮点错误。

mod(round(5.02*100), 10) == 2

您遇到的是floating point错误或工件,就像评论者所说的那样。这不是一个Matlab错误;它只是浮点值的工作原理。您在C或Java中获得相同的结果。浮点值是"近似"类型,因此使用==进行精确的相等比较而没有一些舍入或容差容易出错。

>> isequal(1.02*100, 102)
ans =
     1
>> isequal(5.02*100, 502)
ans =
     0

不是5.02是唯一出现这种情况的数字的情况;约0的几个受到影响。这是一个选择其中几个的例子。

x = 1.02:1000.02;
ix = mod(x .* 100, 10) ~= 2;
disp(x(ix))

要了解此处发生的事情的详细信息(以及您在使用花车时遇到的许多其他情况),请阅读the Wikipedia entry for "floating point"或我最喜欢的文章, "What Every Computer Scientist Should Know About Floating-Point Arithmetic"。 (这个标题很夸张;这篇文章,我不理解它的一半。但它是一个很好的资源。)这个东西与Matlab特别相关,因为Matlab做了一切默认为浮点数。

答案 1 :(得分:4)

这不是MATLAB中的错误。它是浮点运算的限制以及二进制和十进制数之间的转换。即使像0.1这样的简单十进制数也不能精确地表示为具有有限精度的二进制浮点数。

计算机浮点运算通常不精确。虽然我们习惯于处理十进制格式的数字(base10),但计算机以二进制格式(base2)存储和处理数字。用于双精度浮点表示的IEEE标准(参见http://en.wikipedia.org/wiki/Double-precision_floating-point_format,MATLAB使用的内容)指定使用64位来表示二进制数。 1位用于符号,52位用于尾数(数字的实际数字),11位用于指数及其符号(指定小数位所在的位置)。

当您在MATLAB中输入一个数字时,它会立即转换为所有操作和算术的二进制表示,然后转换回十进制以进行显示和输出。

以下是您的示例中发生的情况:

转换为二进制(最多只保留52位数):

5.02 => 1.01000001010001111010111000010100011110101110000101e2  
100  => 1.1001e6  
10   => 1.01e3  
2    => 1.0e1

执行乘法:

    1.01000001010001111010111000010100011110101110000101    e2
  x 1.1001                                                  e6
--------------------------------------------------------------
    0.000101000001010001111010111000010100011110101110000101
    0.101000001010001111010111000010100011110101110000101
  + 1.01000001010001111010111000010100011110101110000101
-------------------------------------------------------------
    1.111101011111111111111111111111111111111111111111111101e8

以52位数切断,给出1.111101011111111111111111111111111111111111111111111e8
请注意,与1.11110110e8相同,即为502.

执行模运算:(此处可能存在其他错误,具体取决于mod()函数中使用的算法)
mod(1.111101011111111111111111111111111111111111111111111e8,1.01e3)= 1.111111111111111111111111111111111111111111100000000e0

误差恰好为-2 -44 ,即-5.6843x10 -14 。十进制和二进制之间的转换以及由于有限精度导致的舍入导致了小的误差。在某些情况下,你很幸运,舍入错误取消了,你仍然可以得到'正确'的答案,这就是为什么你得到你对mod(1.02*100, 10)的期望,但一般情况下,你不能依赖于此。