2012-03-04 14 views
6

Il tipo "float" di Python e il tipo "doppia precisione" di PostgreSQL sono basati sulla stessa implementazione C? Che non può essere il vero problema di fondo qui, ma in ogni caso, ecco cosa ottengo quando provo a manipolare i piccoli numeri in entrambi gli ambienti:Numeri in virgola mobile di Python "float" e PostgreSQL "doppia precisione"

su Python (2.7.2 GCC 4.2.1, se questo è rilevante):

>>> float('1e-310') 
1e-310 

su PostgreSQL (9.1.1):

postgres# select 1e-310::double precision; 
ERROR: "0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001" is out of range for type double precision 

quello che ho capito è che Python tipo float "gestisce" 1e-310, mentre PostgreSQL tipo double precision non lo fa. Entrambi i documenti Python e PostgreSQL su, rispettivamente, tipi "float" e "doppia precisione", si riferiscono allo standard IEEE 754, che dovrebbe essere implementato su "la maggior parte delle piattaforme" (sono su OS X Lion 10.7.3) .

Qualcuno potrebbe spiegare cosa sta succedendo qui? E dammi una soluzione, mi piacerebbe ad esempio "ridurre" la precisione di Python così posso inserire float nel mio database attraverso un Django FloatField. (Il caso di utilizzo completo è che sto leggendo le figure da un file e quindi inserendole).

Alcuni (forse interessante) informazioni aggiuntive, in Python:

>>> sys.float_info 
sys.float_info(max=1.7976931348623157e+308, max_exp=1024, max_10_exp=308, min=2.2250738585072014e-308, min_exp=-1021, min_10_exp=-307, dig=15, mant_dig=53, epsilon=2.220446049250313e-16, radix=2, rounds=1) 
>>> 1e-320.__sizeof__() 
24 

Io davvero non si ottiene il secondo.

+0

avrei speculare che Postgres si rifiuta di dammelo perché .1 non può essere rappresentato esattamente in binario (per la mantissa). – bdares

+0

@bdares Non sono sicuro di aver capito. msgstr "seleziona 1e-100 :: doppia precisione;" funziona bene a Postgres; e non penso che questo sia un problema di esattezza, ma piuttosto uno di precisione – Arthur

risposta

8

Il valore float ('1e-310') è un denormal number che è al di fuori del consueto intervallo di esponenti per float a 53 bit (da +308 a -308) quindi viene memorizzato con minore precisione al fine di ottenere un underflow graduale .

Sembra che il PostgreSQL ha alcuni problemi irrisolti con denormals: http://archives.postgresql.org/pgsql-hackers/2011-06/msg00885.php

Per i valori vicini allo zero, li considerano arrotondamento prima dello stoccaggio nel DB:

>>> round(float('1e-302'), 308) 
1e-302 
>>> round(float('1e-310'), 308) 
0.0 
+3

Grazie! Raffreddare la terra di nessuno. Tuttavia, esiste una regione ancora più ristretta in cui la soluzione non funziona: ad es. round (float ('1e-308'), 308) dà 1e-308 che non è accettato da postgres. Ho semplicemente scelto di fare: if abs (ff) Arthur

Problemi correlati