2013-07-03 6 views
5

La libreria GNU C ha la funzione drem (alias remainder).Come posso simulare la funzione drem/remainder di GNU C Library nel runtime di Python 2.7 di Google App Engine?

Come posso simulare questa funzione utilizzando solo il modules supportato dal runtime di Python 2.7 di Google App Engine?

Dal GNU manual per drem:

Queste funzioni sono come fmod tranne che completano il quoziente n interna all'intero più vicino anziché verso zero a un numero intero. Ad esempio, drem (6.5, 2.3) restituisce -0.4, che è 6.5 meno 6.9.

Dal GNU manual per fmod:

Queste funzioni calcolare il resto della divisione di numeratore per denominatore. In particolare, il valore restituito è numeratore - n * denominatore, dove n è il quoziente del numeratore diviso per denominatore, arrotondato a zero a un numero intero. Quindi, fmod (6.5, 2.3) restituisce 1.9, che è 6.5 meno 4.6.

Leggendo la documentazione il seguente codice Python dovrebbe funzionare:

def drem(x, y): 
    n = round(x/y) 
    return x - n * y 

Tuttavia con Python, drem(1.0, 2.0) == -1.0 e con C drem(1.0, 2.0) == 1.0. Nota Python restituisce negativo e C restituisce positivo. Questa è quasi certamente una differenza interna nei carri di arrotondamento. Per quanto posso dire entrambe le funzioni eseguono lo stesso altrimenti dove i parametri 2 * x != y.

Come posso fare in modo che la mia funzione Python drem funzioni allo stesso modo del suo equivalente C?

+0

Vorrei aggiungere che posso usare solo il [supportato Python moduli] (https://developers.google.com/appengine/kb/libraries) disponibile in Google App Engine. – Dan

+0

'' numpy.round() 'invece di' round() 'sembra funzionare per il mio esempio ma sarei grato di sapere se ci sono casi limite con questo. – Dan

+0

Vorrei ** amare ** non avere dipendenza da Numpy solo per la sua funzione 'round' quindi la domanda rimane valida. – Dan

risposta

5

La chiave per risolvere questo problema è quello di rendersi conto che il drem/remainderfunction specification richiede il calcolo di arrotondamento interno di turno alla metà anche.

Pertanto non è possibile utilizzare la funzione round integrata in Python 2.x mentre si arrotonda a partire da 0. Tuttavia, la funzione round in Python 3.x è stata modificata a metà. Quindi il seguente Python 3.x codice sarà equivalente alla funzione GNU C Library drem ma non funzionerà in Python 2.x:

def drem(x, y): 
    n = round(x/y) 
    return x - n * y 

Per ottenere lo stesso con Python 2.x possiamo usare il modulo decimale e la sua funzione remainder_near :

import decimal 

def drem(x, y): 
    xd = decimal.Decimal(x) 
    yd = decimal.Decimal(y) 

    return float(xd.remainder_near(yd)) 
1

MODIFICA: Ho appena letto il tuo primo commento e vedo che non è possibile utilizzare il modulo ctypes. Ad ogni modo, ho imparato molto oggi cercando di trovare una risposta al tuo problema.

Considerando che il valore di numpy.round() corrisponde esattamente a metà tra i valori decimali arrotondati a next even integer, l'uso di numpy non è una buona soluzione.

Inoltre, chiama internamente questo MONSTER function, che dovrebbe essere difficile da implementare in Python.

Ispirato da this article, ti consiglio di chiamare direttamente la funzione drem dalla libreria matematica. Qualcosa in questo senso dovrebbe fare il trucco:

from ctypes import CDLL 
# Use the C math library directly from Python 
# This works for Linux, but the version might differ for some systems 
libm = CDLL('libm.so.6') 

# For Windows, try this instead: 
# from ctypes import cdll 
# libm = cdll.libc 

# Make sure the return value is handled as double instead of the default int 
libm.drem.restype = c_double 
# Make sure the arguments are double by putting them inside c_double() 
# Call your function and have fun! 
print libm.drem(c_double(1.0), c_double(2.0)) 
+0

La ringrazio molto per l'indagine e per avermi fatto sapere che 'numpy.round' non è praticabile. Sono d'accordo che la funzione interna di drem è mostruosa e non ho intenzione di provare a portarla! Ho aggiornato la domanda in modo che solo l'utilizzo dei moduli di runtime di App Engine sia più importante. Le limitazioni del runtime di App Engine mi sono venute in mente solo dopo aver scritto la domanda e ho cercato di fare esattamente ciò che hai suggerito sopra con i ctype. – Dan

Problemi correlati