The original blog post is here.

In @cfelton 's implementation of `fixbv`

, there are some kinds of round modes implemented in `_resize.py`

, as in the source code:

```
# round :
ROUND_MODES = ( # towards :
'ceil', # +infinity: always round up
'fix', # 0 : always down
'floor', # -infinity: truncate, always round down
'nearest', # nearest : tie towards largest absolute value
'round', # nearest : ties to +infinity
'convergent', # nearest : tie to closest even (round_even)
'round_even', # nearest : tie to closest even (convergent)
)
```

The behavior of `ceil`

, `fix`

and `floor`

is quite clear in this case. Whatever fractional part is, it will be rounded to the integer towards +inf, 0, or -inf.

But it seems not quite clear for the last four modes.

OK, let’s see the source code in `_resize.py`

first:

```
def _round(val, fmt, round_mode):
"""Round the initial value if needed"""
# Scale the value to the integer range (the underlying representation)
assert is_round_mode(round_mode)
assert isinstance(fmt, tuple)
wl,iwl,fwl = fmt
_val = val
val = val * 2.0**fwl
#print(" [rsz][rnd]: %f %f, %s" % (val, _val, fmt))
if round_mode == 'ceil':
retval = math.ceil(val)
elif round_mode == 'fix':
if val > 0:
retval = math.floor(val)
else:
retval = math.ceil(val)
elif round_mode == 'floor':
retval = math.floor(val)
elif round_mode == 'nearest':
fval,ival = math.modf(val)
if fval == .5:
retval = int(val+1) if val > 0 else int(val-1)
else:
retval = round(val)
elif round_mode == 'round':
retval = round(val)
elif round_mode == 'round_even' or round_mode == 'convergent':
fval,ival = math.modf(val)
abs_ival = int(abs(ival))
sign = -1 if ival < 0 else 1
if (abs(fval) - 0.5) == 0.0:
if abs_ival%2 == 0:
retval = abs_ival * sign
else:
retval = (abs_ival + 1) * sign
else:
retval = round(val)
else:
raise TypeError("invalid round mode!" % self.round_mode)
return int(retval)
```

To read the last 4 kinds of resolution, it is necessary to know the behavior of Python’s built-in `round`

function.

Here we assume we do not provide `ndigits`

parameter to `round`

function.

Python’s document says that `round`

will round the numbers to the nearest integer. However, if the fractional part is 0.5, `round`

will round to the nearest even number. That is to say, `round(2.5)`

will be 2, but `round(3.5)`

will be 4.

So, I guess that the behavior of round modes `round`

, `round_even`

, and `convergent`

are the same.

Finally, `nearest`

will be the same as the above three round modes in negative values, but for positive values, it will be different. If the fractional part is 0.5, it will advance to the larger integer, otherwise round to the nearest.

To verify this, I wrote a small program for it. The rounding code is copied from corresponding function in `_resize.py`

.

```
import math
import csv
# round :
ROUND_MODES = ( # towards :
'ceil', # +infinity: always round up
'fix', # 0 : always down
'floor', # -infinity: truncate, always round down
'nearest', # nearest : tie towards largest absolute value
'round', # nearest : ties to +infinity
'convergent', # nearest : tie to closest even (round_even)
'round_even', # nearest : tie to closest even (convergent)
)
def _round(val, round_mode):
if round_mode == 'ceil':
retval = math.ceil(val)
elif round_mode == 'fix':
if val > 0:
retval = math.floor(val)
else:
retval = math.ceil(val)
elif round_mode == 'floor':
retval = math.floor(val)
elif round_mode == 'nearest':
fval,ival = math.modf(val)
if fval == .5:
retval = int(val+1) if val > 0 else int(val-1)
else:
retval = round(val)
elif round_mode == 'round':
retval = round(val)
elif round_mode == 'round_even' or round_mode == 'convergent':
fval,ival = math.modf(val)
abs_ival = int(abs(ival))
sign = -1 if ival < 0 else 1
if (abs(fval) - 0.5) == 0.0:
if abs_ival%2 == 0:
retval = abs_ival * sign
else:
retval = (abs_ival + 1) * sign
else:
retval = round(val)
else:
raise TypeError("invalid round mode!" % self.round_mode)
return int(retval)
values = [-3.5, -3.14, -3., -2.718, -2.5, -2., -1.618, -1.5, -1., -.618, -.5,
0., .5, .618, 1., 1.5, 1.618, 2., 2.5, 2.718, 3., 3.14, 3.5]
with open('round_test.csv', 'w', newline='') as csvfile:
wr = csv.writer(csvfile)
wr.writerow([''] + values)
for round_mode in ROUND_MODES:
rounded_values = [_round(val, round_mode) for val in values]
wr.writerow([round_mode] + rounded_values)
```

It tests different values for different round modes.

Here is the result:

EDIT: The code of “nearest” rounding did not handle the case of negative values, so the condition case should be:

```
if fval == .5 or fval == -.5:
```

And its behavior when the fractional part is 0.5 (either positive or negative) should be rounding away from 0.