Numpy rounding does round towards even, but the other rounding modes can be expressed using a combination of operations.
>>> a=np.arange(-4,5)*0.5
>>> a
array([-2. , -1.5, -1. , -0.5, 0. , 0.5, 1. , 1.5, 2. ])
>>> np.floor(a) # Towards -inf
array([-2., -2., -1., -1., 0., 0., 1., 1., 2.])
>>> np.ceil(a) # Towards +inf
array([-2., -1., -1., -0., 0., 1., 1., 2., 2.])
>>> np.trunc(a) # Towards 0
array([-2., -1., -1., -0., 0., 0., 1., 1., 2.])
>>> a+np.copysign(0.5,a) # Shift away from 0
array([-2.5, -2. , -1.5, -1. , 0.5, 1. , 1.5, 2. , 2.5])
>>> np.trunc(a+np.copysign(0.5,a)) # 0.5 towards higher magnitude round
array([-2., -2., -1., -1., 0., 1., 1., 2., 2.])
In general, numbers of the form n.5 can be accurately represented by binary floating point (they are m.1 in binary, as 0.5=2**-1), but calculations expected to reach them might not. For instance, negative powers of ten are not exactly represented:
>>> (0.1).as_integer_ratio()
(3602879701896397, 36028797018963968)
>>> [10**n * 10**-n for n in range(20)]
[1, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
0.9999999999999999, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]