# Round, With Tie Breakers, Round Two

I published Round, With Ties to Even a couple of days ago. Steve Eddins and Daniel Dolan immediately had substantive comments. Here is my reaction to their comments.

### Contents

#### Two More

The four choices that I described for how to break ties -- 'even', 'odd', 'up' and 'down' -- all have the same behavior for positive and negative numbers. The current built-in round uses the 'up" rule.

Steve sees the need for two more choices that are sensitive to the sign of the number. I will call them 'plus' and 'minus". They round to the right and to the left on the number line. That's sometimes known as round toward plus infinity and toward minus infinity.

#### Sample

Here's a chart of a few values.

    x = (-4.5:1:4.5)';
xRound(x);

     x     round  up  down   even   odd  plus minus

-4.500    -5    -5    -4    -4    -5    -4    -5
-3.500    -4    -4    -3    -4    -3    -3    -4
-2.500    -3    -3    -2    -2    -3    -2    -3
-1.500    -2    -2    -1    -2    -1    -1    -2
-0.500    -1    -1    -0    -0    -1    -0    -1
0.500     1     1     0     0     1     1     0
1.500     2     2     1     2     1     2     1
2.500     3     3     2     2     3     3     2
3.500     4     4     3     4     3     4     3
4.500     5     5     4     4     5     5     4


And the plot.

#### Scaling

The current built-in round also includes the possibility of scaling by a power of 10 to facilitate rounding to, say, the nearest multiple of 1000, or of 1/1000, or three significant figures. Daniel was concerned that having both scaling and tie-breaking options in the same function would be confusing.

But, I think it is OK, because:

• round(x,'even'), the parameter 'even' is a char.
• round(x,3), the parameter 3 is numeric.
• round(x,3,'significant'), the parameter 'significant' is a specific char.

So, the statements

• round(x,'even',3)
• round(x,3,'even')
• round(x,'even',3,'significant')

are unambiguous and distinguishable. After x, the other parameters can be given in any order.

#### round

Here is my proposal for the enhancement request about round. It is available here.

   type round.m

function r = round(varargin)
% r = round(x) scales and rounds the elements of x to the nearest integers.
% Default: ties, elements halfway between integers, are rounded away from zero.
%
% r = round(x,'even') ties round to even integers.
% r = round(x,'odd') ties round to odd integers.
% r = round(x,'up') ties round away from zero (same as default).
% r = round(x,'down') ties round towards zero.
% r = round(x,'plus') ties round to the right on the number line.
% r = round(x,'minus') ties round to the left on the number line.
%
% r = round(x,n), n >= 0, round(10^n*x)/10^n, round(12.3456,2) = 12.3500
% r = round(x,-n), n > 0, 10^n*round(x/10^n), round(1234.56,-2) = 1200.
% r = round(x,n,'significant'), round(.001234,2,'significant') = .0012
% r = round(x,n,'decimals) same as round(x,n).
%
% r = round(x,...), ties, n, 'significant' and 'decimals' can be in any order.
%
% Use Round(...) with capital R to distinguish from built-in round(...).

[x,n,ties] = parse_input(varargin{:});
x = prescale(x,n);

a = abs(x) + 0.5;
r = floor(a);
switch ties
case 'even'
m = (r == a) & (mod(r,2) == 1);
case 'odd'
m = (r == a) & (mod(r,2) == 0);
case 'down'
m = (r == a);
case 'up'
m = [];
case 'plus'
m = (x < 0) & (r == a);
case 'minus'
m = (x > 0) & (r == a);
otherwise
error(['''' ties ''' not recognized.'])
end
r(m) = r(m) - 1;
r = sign(x).*r;

r = postscale(r,n);

% ----------------------------------------------

function [x,n,ties] = parse_input(varargin)
x = varargin{1};
n = zeros(size(x));
ties = 'up';
for k = 2:nargin
if isnumeric(varargin{k})
n(:) = varargin{k};
elseif strcmp(varargin{k},'significant')
n(:) = n(:) - ceil(log10(abs(x(:))));
elseif strcmp(varargin{k},'decimals')
% ignore
else
ties = varargin{k};
end
end
end

function x = prescale(x,n)
if any(n ~= 0)
k = n > 0;
x(k) = 10.^n(k).*x(k);
k = n < 0;
x(k) = x(k)./10.^(-n(k));
end
end

function r = postscale(r,n)
if any(n ~= 0)
k = n > 0;
r(k) = r(k)./10.^n(k);
k = n < 0;
r(k) = 10.^(-n(k)).*r(k);
end
end
end


Published with MATLAB® R2021a

|