Standard numpy round tie breaking is following IEEE 754 convention, to round half towards the nearest even number. Is there a way to specify different rounding behavior, e.g
NumPy doesn't give any control over the internal rounding mode. Here's two alternatives:
gmpy2
, as outlined in this answer. This gives you full control over the rounding mode, but using gmpy2
for simple float math is likely to be slower than NumPy.Use fesetround
via ctypes
to manually set the rounding mode. This is system-specific because the constants may vary by platform; check fenv.h
for the constant values on your platform. On my machine (Mac OS X):
import numpy as np
import ctypes
FE_TONEAREST = 0x0000
FE_DOWNWARD = 0x0400
FE_UPWARD = 0x0800
FE_TOWARDZERO = 0x0c00
libc = ctypes.CDLL('libc.dylib')
v = 1. / (1<<23)
print repr(np.float32(1+v) - np.float32(v/2)) # prints 1.0
libc.fesetround(FE_UPWARD)
print repr(np.float32(1+v) - np.float32(v/2)) # prints 1.0000002
To complete nneonneo answer, if you don't want to download a big package like gmpy2 neither use a system-specific code with ctypes, you can use a binding from C with SWIG (assuming that you already have it on your computer).
Here is what you need to do (in four steps):
1) Write first a file named rounding.i :
%module rounding
%{
/* Put header files here or function declarations like below */
void rnd_arr();
void rnd_zero();
void rnd_plinf();
void rnd_moinf();
void rnd_switch();
%}
extern void rnd_arr();
extern void rnd_zero();
extern void rnd_plinf();
extern void rnd_moinf();
extern void rnd_switch();
2) Then, a file rnd_C.cpp
#include <stdio.h>
#include <stdlib.h>
#include <fenv.h>
void rnd_arr()
{
fesetround(FE_TONEAREST);
}
void rnd_zero()
{
fesetround(FE_TOWARDZERO);
}
void rnd_plinf()
{
fesetround(FE_UPWARD);
}
void rnd_moinf()
{
fesetround(FE_DOWNWARD);
}
void rnd_switch()
{
int r=fegetround();
if (r==FE_UPWARD)
r=FE_DOWNWARD;
else
if (r==FE_DOWNWARD)
r=FE_UPWARD;
else fprintf(stderr,"ERROR ROUDING MODE \n");
fesetround(r);
}
3) In your terminal (if you use another version than python2.7, replace python2.7 at the second line ):
swig -c++ -python -o rounding_wrap.cpp rounding.i
g++ -fPIC -c rounding_wrap.cpp rnd_C.cpp -I/usr/include/python2.7
g++ -shared rounding_wrap.o rnd_C.o -o _rounding.so
4) import the library _rounding.so that you just created by taping at the beginning of your python file :
from your_path_to_rounding.so import rounding