Вопрос

I'm getting a really strange error using the find function in Matlab. Check this out!

A = 0:0.1:10;

now if I do the following I get the expected behavior:

find(A==5.6)
ans = 57

but if I do:

find(A==5.9)
ans =
Empty matrix: 1-by-0

Anyone have any idea why? It is very strange.

Thanks in advance!

Это было полезно?

Решение

The following is common knowledge for most programmers:

a = 0.3;
b = 3 * 0.1;
a == b
ans =
     0

This is because 0.1 can't be represented accurately as a binary number, thus 3*0.1 become almost equal to 0.3, but with round-off errors.

You can however obviously do the following:

a = 0.3;
a == 0.3
ans =
     1   

However, your problem is more complex than this... You did:

A = 0:0.1:10;

Despite what you might think, MATLAB does not create the values [0 0.1 0.2 ...], but rather something along the lines of [0 0+0.1 0+0.1+0.1 0+0.1+0.1+0.1 ...] (but not really, see update in the bottom).

To illustrate this, you can have a look at the following example:

A = 0:0.1:0.4;
find(A == 0.3)
ans =
   Empty matrix: 1-by-0

find(A == 0.1+0.1+0.1)
ans =
     4

This however, does not really cover all aspects:

A = 5.8:0.1:6
A =
    5.8000    5.9000    6.0000

find(A == 5.9)
ans =
     2
%% Found it!

A = 5.8:0.1:6.1
A =
    5.8000    5.9000    6.0000    6.1000

find(A == 5.9)
ans =
   Empty matrix: 1-by-0
%% Didn't find it!

find(A == 5.8+0.1)
ans =
     2
%% Found it again!

For the record, linspace results in the same results.

A = linspace(5.8, 6.0, 3)
A =
    5.8000    5.9000    6.0000

find(A == 5.9)
ans =
     2

A = linspace(5.8, 6.1, 4)
A =
    5.8000    5.9000    6.0000    6.1000

find(A == 5.9)
ans =
   Empty matrix: 1-by-0

find(A == 5.8+0.1)
ans =
     2

So, what's going on? Are the following two actually the same: x = [a:b:c] and y = linspace(a,c,(c-a)/b+1)?

A = 5.8:0.1:6.1
A =
    5.8000    5.9000    6.0000    6.1000

B = linspace(5.8,6.1,4)
B =
    5.8000    5.9000    6.0000    6.1000

A == B
ans =
     1     1     1     1

It might appear that way... But the answer is no, they're not the same!

x = -0.1:0.1:0.3
x =
   -0.1000         0    0.1000    0.2000    0.3000

y = linspace(-0.1,0.3,5)
y =
   -0.1000         0    0.1000    0.2000    0.3000

x == y
ans =
     1     1     0     0     1

So, what happens when you do A = 5.8:0.1:6? How are the numbers created? And how can the following be explained?

A = 5.8:0.1:6;
B = 5.8:0.1:6.1;

A(2)-B(2)
ans =
  8.8818e-016

eps(5.9)
ans =
  8.8818e-016

Update:

To counteract the accumulated errors of doing [0 0+0.1 0+2*0.1 ... 0+k*0.1]

"To counteract such error accumulation, the algorithm of the COLON operator dictates that:

The first half of the output vector is calculated by adding integer multiples of the step to the left-hand endpoint. The second half is calculated by subtracting multiples of the step from the right-hand endpoint.

(See here)

Also have a look here.

The lesson of course is not not compare floating point numbers using x == y, but rather (x - y) < tolerance.

Другие советы

As already pointed out in the comments, it's a floating point issue.

If you really want to use find that way, try using linspace instead of : to create the array:

Before:

>> A = 0:0.1:10;
>> find(A==5.6)

ans =

    57

>> find(A==5.9)

ans =

   Empty matrix: 1-by-0

After:

>> A = linspace(0, 10, 101);
>> find(A==5.6)

ans =

    57

>> find(A==5.9)

ans =

    60
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top