Rounding to the second-nearest integer in MATLAB - matlab

The round function in MATLAB can only round a number to its nearest integer. How can we round a number to its second-nearest integer?
For example, for 10.3, we get 11; for 10.6, we get 10.

You could use the following logic
round2 = #(x) round( floor(x) + 1 - rem(x,1) );
The logic here is:
Round down to the nearest integer with floor(x)
Flip the fractional part (i.e. 0.6 becomes 0.4) with 1-rem(x,1)
Add these together and round normally
A side effect of this is integers get "rounded" up to the next integer.
Test:
round2 = #(x) round( floor(x) + 1 - rem(x,1) );
a = [10.3, 10.6, 11];
round2(a)
% ans = [11, 10, 12]

Thank you for your suggestions.
I found a tricky way to solve this problem.
round2 = #(x) round(x) + sign(x-round(x));
The logic is:
Find the relationship between the input and its nearest integer (-1 for x<round(x); 1 for x>round(x)) with sign(x-round(x)).
Correct the result (round(x)) toward the direction of x.
Example
a = [-10.6, -10.4, 0, 10.4, 10.6];
round2(a)
% ans = [-10, -11, 0, 11, 10]
In this solution, the result of an integer is itself.

Related

Add number to all negative values in a 4D matrix

I have a matrix DirModel of dimension 2x2x29x1739. I want to add 360 to all negative values in this matrix, but the code I use doesn't keep up the dimensions of this matrix, it makes it into an array:
Neg=DirModel<0;
DirModel2=DirModel(Neg)+360;
I found several combinations of this online but non of them seem to keep up the dimensions. I would like to do it without using loops.
Any answer is appreciated!
You could boil it all down to a one-liner by making use of logical indices:
DirModel(DirModel<0) = DirModel(DirModel<0) + 360
How about the following code?
>> DirModel = rand(2, 2, 29, 1739) - 0.5;
>> Neg = (DirModel < 0);
>> DirModel2 = DirModel;
>> DirModel2(Neg) = DirModel2(Neg) + 360;
>> DirModel(:, :, 1, 1)
ans =
0.169128 -0.180931
0.055867 0.339892
>> DirModel2(:, :, 1, 1)
ans =
0.169128 359.819069
0.055867 0.339892
Let's check what's happening:
>> Neg = (DirModel < 0);
Neg is a 2 x 2 x 29 x 1739 logical matrix, in which 1s indicate indices where DirModel has negative values.
>> DirModel2 = DirModel;
This assignment ensures, that all values are copied and that the matrix dimensions are preserved.
>> DirModel2(Neg) = DirModel2(Neg) + 360;
Only add 360 to those matrix elements, whose value has been negative in the original DirModel.
Your assignment
DirModel2=DirModel(Neg)+360
initiates the new DirModel2 matrix directly, and only addresses the negative values of DirModel. Check the total number of elements of your resulting DirModel2! Therefore, MATLAB has no reason to preserve the matrix dimensions.
As a one-line answer, I suggest DirModel2 = mod(DirModel,360) + ~mod(DirModel,360)*360;
mod(DirModel,360) alone will add 360 to any negative number but it will also bring 360 to 0. To avoid this, we add 360 if the result of mod(DirModel,360) is 0 (i.e. ~mod(DirModel,360) is 1).
With new information from OP, initial data being between -180 and 180, and no problem if 0 is changed to 360, I simply recommand
DirModel2 = mod(DirModel,360);

Quantizing an image in matlab

So I'm trying to figure out why my code doesn't seem to be displaying the properly uniformed quantized image into 4 levels.
Q1 =uint8(zeros(ROWS, COLS, CHANNELS));
for band = 1 : CHANNELS,
for x = 1 : ROWS,
for y = 1 : COLS,
Q1(ROWS,COLS,CHANNELS) = uint8(double(I1(ROWS,COLS,CHANNELS) / 2^4)*2^4);
end
end
end
No5 = figure;
imshow(Q1);
title('Part D: K = 4');
It is because you are not quantifying. You divide a double by 16, then multiply again by 16, then convert it to uint8. The right way to quantize is to divide by 16, throw away any decimals, then multiply by 16:
Q1 = uint8(floor(I1 / 16) * 16);
In the code snippet above, I assume I1 is a double. Convert it to double if its not: I1=double(I1).
Note that you don't need the loops, MATLAB will apply the operation to each element in the matrix.
Note also that if I1 is an integer type, you can do something like this:
Q1 = (uint8(I1) / 16) * 16;
but this is actually equivalent to replacing the floor by round in the first example. This means you get an uneven distribution of values: 0-7 are mapped to 0, 8-23 are mapped to 16, etc. and 248-255 are all mapped to 255 (not a multiple of 16!). That is, 8 numbers are mapped to 0, and 8 are mapped to 255, instead of mapping 16 numbers to each possible multiple of 16 as the floor code does.
The 16 in the code above means that there will be 256/16=16 different grey levels in the output. If you want a different number, say n, use 256/n instead of 16.
It's because you are using ROWS, COLS, CHANNELS as your index, it should be x,y,band. Also, the final multiplication of 2^4 has be after the uint8 cast otherwise no rounding ever takes place.
In practice you should avoid the for loops in Matlab since matrix operations are much faster. Replace your code with
Q1=uint8(double(I1/2^4))*2^4
No5 = figure;
imshow(Q1);
title('Part D: K = 4');

Explain MATLAB function smooth(x,y,span,'moving')

I recently came across the Matlab smooth function used as follows:
ans = smooth(x, y, span, 'moving');
The Matlab documentation states
yy = smooth(x,y,...) additionally specifies x data. If x is not provided, methods that require x data assume x = 1:length(y). You should specify x data when it is not uniformly spaced or sorted. If x is not uniform and you do not specify method, lowess is used. If the smoothing method requires x to be sorted, the sorting occurs automatically.
However, I am unclear as to what this actually means for the 'moving' average case. Is x an index for the y data, and if so how do non-integer values of x affect the 'moving' average of y?
Moving average means each value of the yy (or ans in your case) is an average of the n closest points. https://en.wikipedia.org/wiki/Moving_average
There are several methods to calculate it - it depends on WHICH POINTS we will use. For example:
( (i-1) + (i-2) + ... + (i-n) )/n;
where n - is a span or linear filtration level.
This mean that first three points can't be calculated (there are no data for it). And sometimes result must be shifted (because really - average of the first 4 points not really corresponds to 4th elements).
So Matlab use another method:
yy(1) = y(1)
yy(2) = (y(1) + y(2) + y(3))/3
yy(3) = (y(1) + y(2) + y(3) + y(4) + y(5))/5
yy(4) = (y(2) + y(3) + y(4) + y(5) + y(6))/5
...
It's more useful.
About x and y - it is usual 2d-data: each x corresponds to each y. you can avoid setting of x, then matlab will use [1, 2, 3, ..., length(y)] sequence for this. But if you have some non-uniformly distributed data you have to set it for getting right result. So if you have non-integer values it will works correct, scaling it for x axis. Here the easiest example from my head:
Say you have data y corrupted by noise and let's assume y = [2.1, 3.2, 1.7, 4.5, 5.8, 6.9]. Let's say that you have decided to use moving average of 3 window filter to smooth y.
smoothedY1 = (2.1 + 3.2 + 1.7)/3 = 2.3333
smoothedY2 = (3.2 + 1.7 + 4.5)/3 = 3.1333
smoothedY3 = (1.7 + 4.5 + 5.8)/3 = 4.0000
smoothedY3 = (4.5 + 5.8 + 6.9)/3 = 5.7333
Pay attention to the way corrupted data is being shifted to the left by one element per iteration. Now let's use smooth() in Matlab.
y = [2.1, 3.2, 1.7, 4.5, 5.8, 6.9];
smooth(y, 3, 'moving')
The above script yields the following result
ans =
2.1000
2.3333 <----
3.1333 | (smoothed data)
4.0000 |
5.7333 <----
6.9000
To answer your original question, the "x" data is just used for sorting, but is otherwise ignored when the method is 'moving':
>> x = rand(10, 1);
>> y = (1:10)' + 0.1*randn(10,1);
>> isequal(smooth(x,y,'moving'), smooth(y,'moving'))
ans =
0
>> z = sortrows([x y], 1);
>> isequal(smooth(z(:,1),z(:,2),'moving'), smooth(z(:,2),'moving'))
ans =
1
The "x" values aren't actually taken into account for the averaging, they are just used to sort "y" by increasing index.

Stability (Numerical analysis)

I'm trying to find the max machine number x that satisfies the following equation: x+a=a, where a is a given integer. (I'm not allowed to use eps.)
Here's my code (which is not really working):
function [] = Largest_x()
a=2184;
x=0.0000000001
while (x+a)~=a
x=2*x;
end
fprintf('The biggest value of x in order that x+a=a \n (where a is equal to %g) is : %g \n',a,x);
end
Any help would be much appreciated.
The answer is eps(a)/2.
eps is the difference to the next floating point number, so if you add half or less than that to a float, it won't change. For example:
100+eps(100)/2==100
ans =
1
%# divide by less than two
100+eps(100)/1.9==100
ans =
0
%# what is that number x?
eps(100)/2
ans =
7.1054e-15
If you don't want to rely on eps, you can calculate the number as
2^(-53+floor(log2(a)))
You're small algorithm is certainly not correct. The only conditions where A = X + A are when X is equal to 0. By default matlab data types are doubles with 64 bits.
Lets pretend that matlab were instead using 8 bit integers. The only way to satisfy the equation A = X + A is for X to have the binary representation of [0 0 0 0 0 0 0 0]. So any number between 1 and 0 would work as decimal points are truncated from integers. So again if you were using integers A = A + X would resolve to true if you were to set the value of X to any value between [0,1). However this value is meaningless because X would not take on this value but rather it would take on the value of 0.
It sounds like you are trying to find the resolution of matlab data types. See this: http://www.mathworks.com/help/matlab/matlab_prog/floating-point-numbers.html
The correct answer is that, provided by Jonas: 0.5 * eps(a)
Here is an alternative for the empirical and approximate solution:
>> a = 2184;
>> e = 2 .^ (-100 : 100); % logarithmic scale
>> idx = find(a + e == a, 1, 'last')
idx =
59
>> e(idx)
ans =
2.2737e-013

how to eliminate complex number in a vector in Matlab

In Matlab, suppose there is a vector whose elements can be complex or real. I was wondering how to remove the nonreal elements, and consequently reduce the size of the vector? Thanks and regards!
Use the REAL and IMAG functions:
>> x = [1+i; 4+3i; 5+6i]
x =
1 + 1i
4 + 3i
5 + 6i
>> real(x)
ans =
1
4
5
>> imag(x)
ans =
1
3
6
EDIT
The above doesn't answer the poster's question. This does.
Use the FIND and REAL functions:
>> v = [1+i; 2; 3]
v =
1 + 1i
2
3
>> v(v == real(v))
ans =
2
3
You can also avoid testing in a loop using Matlab's vector syntax:
x = [1, 2, 3+1i, 4+2i, 5+3i, 6, 7, 8+4i, 9+0.000001i]
y = x(imag(x) == 0);
z = real(x(abs(imag(x)) < 0.00001));
y should be [1,2,6,7] and z should be [1,2,6,7,9]
imag(x) == 0 yields a logical vector with true values whenever the equality condition holds. x(<logical vector>) yields a new vector with only the elements of x where <logical vector> was true.
That's a very unusual thing to ask. Since the imaginary part is a floating point number, you can't really tell which number is a real number and which number is very close to a real number. Such function doesn't exist in Matlab since it's not very clear how it would be useful for anything (it doesn't make much sense to remove those numbers). Specifying your actual purpose here might help you get better answers.
If you want to ensure that only real numbers are left in the vector, you can use the following (it doesn't work with matrices and vertical rows, but you've got the idea):
x = [1, 2, 3+1i, 4+2i, 5+3i, 6, 7, 8+4i, 9+0i]
z = []
for k = [1:length(x)]
if imag(x(k)) == 0
z = [z, real(x(k))]
endif
endfor
If you want to keep all numbers that are close to a real number, but could have some small non-zero imaginary part, you can use the following:
x = [1, 2, 3+1i, 4+2i, 5+3i, 6, 7, 8+4i, 9+0.000001i]
z = []
for k = [1:length(x)]
if abs(imag(x(k))) < 0.00001
z = [z, real(x(k))]
endif
endfor
Of course, if you tell us what your actual criterion is, it would be much easier to give you a better idea. Are you looking for the real solutions to some sort of equation or system of equations, real roots of a polynomial? In this case, the first one might miss a real solution because of the approximation error, and the second one can give you things that aren't solutions.