2013-04-14 4 views
7

Die standardmäßige numpy runde tie breaking folgt der IEEE 754 Konvention, um die Hälfte auf die nächste gerade Zahl zu runden. Gibt es eine Möglichkeit, ein anderes Rundungsverhalten anzugeben, z. rund in Richtung Null oder in Richtung -inf? Ich spreche nicht über Decke oder Boden, ich brauche nur andere Krawatte brechen.Tie breaking of round mit numpy

+3

Aus Neugier, wie können diese Tie-Regeln zu brechen in der Praxis relevant werden? Immerhin liegt der Unterschied in der gleichen Größenordnung wie der Quantisierungsfehler. – maxy

+1

Ich rekonstruiere einige komplexe Berechnungen von Matlab in Python. Die Krawatte, die dort bricht, ist anders, also ruiniert es einige Testfälle, wenn ich die Ergebnisse vergleiche. – Michael

Antwort

9

NumPy gibt keine Kontrolle über den internen Rundungsmodus. Hier sind zwei Alternativen:

  1. Verwenden gmpy2, wie in this answer skizziert. Dies gibt Ihnen die volle Kontrolle über den Rundungsmodus, aber gmpy2 für einfache float-Mathematik ist wahrscheinlich langsamer als NumPy.
  2. Verwenden Sie fesetround über ctypes, um den Rundungsmodus manuell festzulegen. Dies ist systemspezifisch, da die Konstanten je nach Plattform variieren können. Überprüfen Sie fenv.h für die konstanten Werte auf Ihrer Plattform. Auf meinem Rechner (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 
    
+5

Danke für Ihre Antwort! Der Vollständigkeit halber: Mit linux fand ich fesetround nicht in libc, sondern in libm, also war die Ladezeile 'libm = ctypes.CDLL ('libm.so.6')'. Die Konstanten sind gleich. – Michael

0

Mit dem Open-Source-Software SWIG

nneonneo Antwort zu vervollständigen, wenn Sie nicht über ein großes Paket wie gmpy2 weder Gebrauch herunterladen möchten Ein systemspezifischer Code mit Ctypes, Sie können eine Bindung von C mit SWIG verwenden (vorausgesetzt, Sie haben es bereits auf Ihrem Computer).

Hier ist, was Sie tun müssen (in vier Stufen):

1) zunächst eine Datei mit dem Namen 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) Dann wird eine Datei 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 Ihrem Terminal (wenn Sie eine andere Version als python2.7 verwenden, python2.7 in der zweiten Zeile ersetzen):

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) die Bibliothek _rounding.so importieren, die Sie gerade durch Abkleben am Anfang Ihres Python-Datei erstellt:

from your_path_to_rounding.so import rounding