Tie breaking of round with numpy

后端 未结 2 1953
臣服心动
臣服心动 2020-12-10 05:58

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

相关标签:
2条回答
  • 2020-12-10 06:10

    NumPy doesn't give any control over the internal rounding mode. Here's two alternatives:

    1. Use 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.
    2. 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
      
    0 讨论(0)
  • 2020-12-10 06:28

    With the open-source software SWIG

    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 
    
    0 讨论(0)
提交回复
热议问题