1

I would like to implement a function very similar to the floor function, but instead of rounding towards the nearest integer, I would like it to round any number(s) according to a specified array, and I would like to code this in Matlab.

For example, I have a set of arbitrary array of numbers given by:

A = [-1.1778, 1.3657, 2.9880, -0.5674].

I then have a second array of integers as:

Q = [-3, -1, 1, 3].

I would like to each element of A as you would using the floor function, but they must round to one of the integers given in Q.

So A(3) = 2.9880 must be rounded to 1, since it is the largest integer in the given set Q that is smaller or equal to it. Likewise, A(1) = -1.1778 must be rounded to -3.

The closest I have come is rounding numbers according to a specific set, but I could not figure out how to round down or up, specifically.

My best attempt is shown below:

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function s_hat = roundSet(num_array, integer_set)
C = zeros(length(integer_set), length(num_array));
s_hat = zeros(1, length(num_array));
    for ii = 1:length(num_array)
    for jj = 1:length(integer_set)
        C(jj, ii) = abs(num_array(ii) - integer_set(jj));
    end
    end
    [~, i] = min(C, [], 1);
    for ii = 1:length(i)
    s_hat(ii) = integer_set(i(ii));
    end
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

The code rounds numbers in a according to the nearest elements in b, but does not round up or down, it just rounds the numbers off. If I can solve this problem, I can also implement a similar that rounds up, like the ceiling function.

Any help would be greatly appreciated.

Thank you.

Yash
  • 21
  • 2
  • You appear to be content with a linear search of Q, but this could get very slow as the array sizes increase. For larger array sizes, it would be better to sort Q and do a binary search. – Simon Goater Jul 10 '23 at 09:14
  • It looks like Q is sorted, so I would add a conditional statement to your last `for loop`. It is not elegant though! ```matlab for ii = 1:length(i) s_hat(ii) = integer_set(i(ii)); if(s_hat(ii)>num_array(ii)) s_hat(ii)=integer_set(i(ii-1)); end end ``` – Praveen Jul 10 '23 at 09:22

1 Answers1

0

If you can assume that there is always a valid option within Q for each A, so in the "floor" case there must be some element of Q which is lower than all elements in A, you can do this via interpolation.

Interpolate elements of A onto the domain 1:N for where Q has N elements. Then you can use any normal rounding operation (floor, ceil, round) to get what's basically the index of Q, then use that index.

% Setup
A = [-1.1778, 1.3657, 2.9880, -0.5674];
Q = [-3, -1, 1, 3];

% Interpolate A onto domain 1,2,...,numel(Q)
Qx = 1:numel(Q);
Ai = interp1( Q, Qx, A, 'linear' ); % = [1.911, 3.18, 3.99, 2.22]
% Do some rounding
Ai = floor( Ai ); % = [1,3,3,2] = index within Q 
Ai = Q( Ai );     % = [-3,1,1,-1] = final "rounded" value to elements of Q

The interpolation preserves which element of Q each element of A is closest to, but puts you on an axis of consecutive positive integers which makes the indexing into Q possible.

Replacing floor with ceil in the above example results in Ai = [-1,3,3,1] which is the expected result for this example for this change in the rounding method.

Wolfie
  • 27,562
  • 7
  • 28
  • 55