views:

63

answers:

2

Take this simple example:

a = [1 2i];

x = zeros(1,length(a));
for n=1:length(a)
    x(n) = isreal(a(n));
end

In an attempt to vectorize the code, I tried:

y = arrayfun(@isreal,a);

But the results are not the same:

x =
     1     0
y =
     0     0

What am I doing wrong?

+5  A: 

This certainly appears to be a bug, but here's a workaround:

>> y = arrayfun(@(x) isreal(x(1)),a)

ans =

     1     0

Why does this work? I'm not totally sure, but it appears that when you perform an indexing operation on the variable before calling ISREAL it removes the "complex" attribute from the array element if the imaginary component is zero. Try this in the Command Window:

>> a = [1 2i];         %# A complex array
>> b = a(1);           %# Indexing element 1 removes the complex attribute...
>> c = complex(a(1));  %# ...but we can put that attribute back
>> whos
  Name       Size            Bytes  Class      Attributes

  a          1x2                32  double     complex   
  b          1x1                 8  double                  %# Not complex
  c          1x1                16  double     complex      %# Still complex

Apparently, ARRAYFUN must internally maintain the "complex" attribute of the array elements it passes to ISREAL, thus treating them all as being complex numbers even if the imaginary component is zero.

gnovice
By the way, the bug does not appear in GNU Octave.
KennyTM
you are right, according to the documentation of the COMPLEX function, `isreal(1+0i)` is not the same as `isreal(complex(1,0))`
Dave
+5  A: 

It might help to know that MATLAB stores the real/complex parts of a matrix separately. Try the following:

>> format debug
>> a = [1 2i];
>> disp(a)

Structure address = 17bbc5b0 
m = 1
n = 2
pr = 1c6f18a0 
pi = 1c6f0420
   1.0000                  0 + 2.0000i

where pr is a pointer to the memory block containing the real part of all values, and pi pointer to the complex part of all values in the matrix. Since all elements are stored together, then in this case they all have a complex part.

Now compare these two approaches:

>> arrayfun(@(x)disp(x),a)

Structure address = 17bbcff8 
m = 1
n = 1
pr = 1bb8a8d0 
pi = 1bb874d0
     1

Structure address = 17c19aa8 
m = 1
n = 1
pr = 1c17b5d0 
pi = 1c176470
        0 + 2.0000i

versus

>> for n=1:2, disp(a(n)), end

Structure address = 17bbc930 
m = 1
n = 1
pr = 1bb874d0 
pi = 0
     1

Structure address = 17bbd180 
m = 1
n = 1
pr = 1bb874d0 
pi = 1bb88310
        0 + 2.0000i

So it seems that when you access a(1) in the for loop, the value returned (in the ans variable) has a zero complex-part (null pi), thus is considered real.

One the other hand, ARRAYFUN seems to be directly accessing the values of the matrix (without returning them in ANS variable), thus it has access to both pr and pi pointers which are not null, thus are all elements are considered non-real.

Please keep in mind this just my interpretation, and I could be mistaken...

Amro
wow, I didn't know about this debug option
Dave
I have to thank @Mikhail for the this tip: http://stackoverflow.com/questions/1735841/initializing-a-ublas-vector-from-a-c-array/1735997#1735997 (see the comments)
Amro

related questions