Elegant way of finding all integer element indices in a MATLAB array? - matlab

I have a double array containing a mixture of integers and doubles. I wish to get all the indices of the integer elements. My way (see below) is quite ugly.
idx_list = [];
for idx = 1:numel(A)
if isinteger(A(idx))
idx_list = [idx_list idx];
end
end
I believe there is a one liner / a more elegant way.

Something like this would find perfect integers -
idx_list = find( floor(A) == A )
Changing floor to ceil or round or fix should do it too.
If you want to take care of floating point precision issues, you can introduce eps here -
idx_list = find(abs(round(A) - A)<eps(round(A)))

Related

Extract digits to the right of the decimal point

e.g. x = 12.354
I want to get 354 from x. For this I tried this equation,
y = x - floor(x)
But this generates 0.354 which is not my requirement.
So, how can I do it?
The generic idea as pointed out by #JoachimPileborg looks like this in MATLAB:
x = 12.354;
str = num2str(x);
idx = find(str=='.');
substr = str(idx+1:end);
y = str2num(substr);
A generic solution that should work with all programming languages, is to convert the number to a string, then take the sub-string from after the decimal point (or comma) and convert it to an integer.
An alternative (possibly faster) to m.s. 's answer. Notice the 'shift' due to this approach effectively removing the zeroes to the right of the decimal point.
yfoo = 34.00267400;
yfoo = yfoo- floor(yfoo); % .00267400;
% internal rep of number ignores trailing zeros.
yrab = str2num(strrep(num2str(yfoo),'.','')); %2674

Wrong value while summing floats in matlab

while (tempsumf ~= sum)
iter = iter + 1;
tempsumf = tempsumf + fitness(iter, 1);
if (tempsumf > sel1)
break;
end
end
I have an array(fitness) of floats here (mostly with exponent -6/-5) which i am summing up in tempsumf ... now when the loop goes to the second iteration, i get the value 5.000 which is utterly wrong. I can figure out the issue.
This is probably due to floating point precision. You shouldn't do equality or inequality tests on double precision numbers. Instead of while (tempsumf ~= sum), use while (abs(tempsumf - sum))>1e-6) or whatever threshold you deem appropriate.
See the MATLAB wiki entry on this topic for more information.
Second possible cause of the error: you are overwriting the built-in function sum with your variable sum. Don't do that! Call your variable my_sum or something similar.

How can I vectorize a large number of subtractions in Matlab

I have one array (the "true" cartesian coordinates) which is of size (natoms*3,1) where natoms is the number of atoms. I also have a large number (500,000) of observations stored in an array of size (nobs, natoms*3). Now, I want to create an array of the differences between all observations against the true coordinates. I would like to simply vectorize this by doing something like
for iat = 1:natoms
xyz_dif = xyz_obs(:, 3*iat-2:3*iat) - xyz_true(3*iat-2:3*iat)
end
but this does not work. Instead I am forced to go through each of the observtions like so:
for iat = 1:natoms
for iobs = 1:nobs
xyz_diff(iobs, 3*iat-2:3*iat) = xyzs(iobs, 3*iat-2:3*iat) - xyz_true(3*iat-2:3*iat)
end
end
but this seems quite inefficient. Is there a faster, more efficient way to do this?
Thanks.
use bsxfun
xyz_diff = bsxfun(#minus, xyz_true', xyz_obs)
an alternative solution, which in my view is more readable is to use matrix multiplication:
xyz_diff = xyz_obs-ones(nobs,1)*xyz_true;

How to find the position(index) of a floating point number in matrix in MATLAB?

I am writing a function wherein I need to read a 6501 X 1 matrix and then find the index of a specific number which is provided by the user as an input. I am able to find the position of integer values but not of floating point numbers which are present in the column. Can anyone please help? Thank you
Below is the part of the function which loops through the column matrix to find the index of a number
format short g
columnmzData = mzData; % mzData is the column matrix
length = size(columnmzData);
i=1;
for mzDataLoop = 1:6501
if (columnmzData(mzDataLoop) == mzValue)
mzValueIndice = i
break;
else
i=i+1;
end
end
Here is the part of the column matrix:
1498
1498.2
1498.4
1498.6
1498.8
1499
1499.2
1499.4
1499.6
1499.8
For floating point numbers rather look for a tiny difference than perfect equality so in your code columnmzData(mzDataLoop) == mzValue becomes abs(columnmzData(mzDataLoop) - mzValue) < tol where tol is a very small and depends on the tolerance of your numbers.
Have a look at this question to understand better
However you shouldn't be using a loop at all! Try the find function:
mzValueIndice = find(columnmzData == mzValue) %for ints
mzValueIndice = find(abs(columnmzData - mzValue) < tol) %for floats
Finding the exact float value is hard, maybe you can specify a tolerance?
if (abs(columnmzData(mzDataLoop) - mzValue) < tolerance)

Replace values in matrix with other values

I have a matrix with integers and I need to replace all appearances of 2 with -5. What is the most efficient way to do it? I made it the way below, but I am sure there is more elegant way.
a=[1,2,3;1,3,5;2,2,2]
ind_plain = find(a == 2)
[row_indx col_indx] = ind2sub(size(a), ind_plain)
for el_id=1:length(row_indx)
a(row_indx(el_id),col_indx(el_id)) = -5;
end
Instead of loop I I seek for something like: a(row_indx,col_indx) = -5, which does not work.
find is not needed in this case.
Use logical indexing instead:
a(a == 2) = -5
In case of searching whether a matrix is equal to inf you should use
a(isinf(a)) = -5
The general case is:
Mat(boolMask) = val
where Mat is your matrix, boolMask is another matrix of logical values, and val is the assignment value
Try this:
a(a==2) = -5;
The somewhat longer version would be
ind_plain = find(a == 2);
a(ind_plain) = -5;
In other words, you can index a matrix directly using linear indexes, no need to convert them using ind2sub -- very useful! But as demonstrated above, you can get even shorter if you index the matrix using a boolean matrix.
By the way, you should put semicolons after your statements if (as is usually the case) you're not interested in getting the result of the statement dumped out to the console.
The Martin B's method is good if you are changing values in vector. However, to use it in matrix you need to get linear indices.
The easiest solution I found is to use changem function. Very easy to use:
mapout = changem(Z,newcode,oldcode)
In your case: newA = changem(a, 5, -2)
More info: http://www.mathworks.com/help/map/ref/changem.html
Here's a trivial, unoptimised, probably slow implementation of changem from the Mapping Toolbox.
function mapout = changem(Z, newcode, oldcode)
% Idential to the Mapping Toolbox's changem
% Note the weird order: newcode, oldcode. I left it unchanged from Matlab.
if numel(newcode) ~= numel(oldcode)
error('newcode and oldcode must be equal length');
end
mapout = Z;
for ii = 1:numel(oldcode)
mapout(Z == oldcode(ii)) = newcode(ii);
end
end