# Round, With Tie Breakers, Round Three

I recently published Round, With Ties to Even and followed that with Round Two. Then, in an email, Andy Bartlett pointed out that my new `round` function fails for some large values of `x` between `flintmax/2` and `flintmax`.

### Contents

`flintmax/2`

The quantity `f = flintmax/2` is equal to `2^52`, which is `1/eps`. The `help` entry for `format bank` says it is a fixed format for dollars and cents. That's true, but I also like to use it for displaying large flints.

```
format bank
f = flintmax/2
```

f = 4503599627370496.00

The numbers in the interval `[f flintmax]` are the *largest* flints. They are all integers. The spacing between them is one.

eps(f)

ans = 1.00

All floating point numbers larger than `flintmax` are integers, but the spacing between is larger than one, so they cannot be used for integer arithmetic.

#### Rounding

The idea behind all versions of `round` is the following. Suppose `abs(x)` is between two integers, `y-1` and `y`. Then

a = abs(x) + 0.5;

is between `y-0.5` and `y+0.5`. And

r = floor(a);

is equal to either `y-1` or `y`, whichever is closer to `abs(x)`.

That idea works for almost all `x`. However, if `x` is between `f` and `flintmax`, the quantity `x + 0.5` is not a floating point number and must itself be rounded to the nearest even by the addition hardware. If `y` is odd, the resulting `a` will be `y+1`, which is too large.

So, I must compute `a` by

a = abs(x) + (0.5 - eps/4);

The quantity `(0.5 - eps/4)` is the next smaller floating point number less that `0.5`.

`round`

This is the resulting proposal for the enhancement request on `round`. It is available here. Only the line computing `a` has changed from Round Two.

```
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-eps/4); 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

#### test

The vector `x = f:flintmax` would have `2^52+1` elements. That's too many. The first four and the last four is enough.

format hex x = [f+(0:3); 2*f-(3:-1:0)] r = Round(x) up = Round(x,'up') down = Round(x,'down') even = Round(x,'even') odd = Round(x,'odd') plus = Round(x,'plus') minus = Round(x,'minus')

x = 4330000000000000 4330000000000001 4330000000000002 4330000000000003 433ffffffffffffd 433ffffffffffffe 433fffffffffffff 4340000000000000 r = 4330000000000000 4330000000000001 4330000000000002 4330000000000003 433ffffffffffffd 433ffffffffffffe 433fffffffffffff 4340000000000000 up = 4330000000000000 4330000000000001 4330000000000002 4330000000000003 433ffffffffffffd 433ffffffffffffe 433fffffffffffff 4340000000000000 down = 432ffffffffffffe 4330000000000000 4330000000000001 4330000000000002 433ffffffffffffc 433ffffffffffffd 433ffffffffffffe 433fffffffffffff even = 4330000000000000 4330000000000000 4330000000000002 4330000000000002 433ffffffffffffc 433ffffffffffffe 433ffffffffffffe 4340000000000000 odd = 432ffffffffffffe 4330000000000001 4330000000000001 4330000000000003 433ffffffffffffd 433ffffffffffffd 433fffffffffffff 433fffffffffffff plus = 4330000000000000 4330000000000001 4330000000000002 4330000000000003 433ffffffffffffd 433ffffffffffffe 433fffffffffffff 4340000000000000 minus = 432ffffffffffffe 4330000000000000 4330000000000001 4330000000000002 433ffffffffffffc 433ffffffffffffd 433ffffffffffffe 433fffffffffffff

**Category:**- Numerical Analysis,
- Precision,
- Programming

## Comments

To leave a comment, please click here to sign in to your MathWorks Account or create a new one.