La rottura del tiepido numero di round standard segue la convenzione IEEE 754, per arrotondare la metà verso il numero pari più vicino. C'è un modo per specificare un diverso comportamento di arrotondamento, ad es. giro verso lo zero o verso -inf? Non sto parlando di ceil o floor, ho solo bisogno di un tie break diverso.Rottura del round con numpy
risposta
NumPy non dà alcun controllo sulla modalità di arrotondamento interno. Ecco due alternative:
- Utilizzare
gmpy2
, come indicato nella this answer. Questo ti dà il pieno controllo sulla modalità di arrotondamento, ma l'utilizzo digmpy2
per la matematica a virgola mobile è probabilmente più lento di NumPy. Utilizzare
fesetround
tramitectypes
per impostare manualmente la modalità di arrotondamento. Questo è specifico del sistema perché le costanti possono variare a seconda della piattaforma; controllafenv.h
per i valori costanti sulla tua piattaforma. Sulla mia macchina (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
Grazie per la tua risposta! Per completezza: usando linux, ho trovato fesetround non in libc, ma in libm, quindi la linea di caricamento era 'libm = ctypes.CDLL ('libm.so.6')'. Le costanti sono le stesse. – Michael
Con il software open-source SWIG
Per completare la risposta nneonneo, se non si desidera scaricare un pacchetto grande come gmpy2 né l'uso un codice specifico per il sistema con ctypes, è possibile utilizzare un'associazione da C con SWIG (presumendo che sia già presente sul computer).
Ecco cosa dovete fare (in quattro fasi):
1) prima un file denominato 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) Quindi, un 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) Nel vostro terminale (se si utilizza un'altra versione di python2.7, sostituire python2.7 alla seconda riga):
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) importare il _rounding.so libreria appena creata con nastro adesivo all'inizio del file python:
from your_path_to_rounding.so import rounding
Per curiosità, come possono queste regole tie-breaking diventare rilevante in pratica? Dopo tutto, la differenza è nello stesso ordine di grandezza dell'errore di quantizzazione. – maxy
Sto ricostruendo alcuni calcoli complessi da MATLAB in python. La rottura del legame è diversa, quindi rovina alcuni casi di test, quando confronto i risultati. – Michael