Reputation: 1984
Are Python's "float" type and PostgreSQL's "double precision" type based on the same C implementation? That may not be the real underlying problem here, but anyway, here's what I get when I try to manipulate small numbers in both environments:
On Python (2.7.2 GCC 4.2.1, if that's relevant):
>>> float('1e-310')
1e-310
On PostgreSQL (9.1.1):
postgres# select 1e-310::double precision;
ERROR: "0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001" is out of range for type double precision
What I understand is that Python float type "handles" 1e-310 while PostgreSQL double precision type does not. Both Python and PostgreSQL docs on, respectively, "float" and "double precision" types, refer to the IEEE 754 standard, which is supposed to be implemented on "most platforms" (I'm on OS X Lion 10.7.3).
Could anyone explain what's happening here? And give me a solution, I'd like for instance to "reduce" Python precision so I can insert floats in my database through a Django FloatField. (The full use case is that I'm reading figures from a file and then inserting them).
Some (maybe interesting) additional information, 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
I really don't get the second one.
Upvotes: 8
Views: 5449
Reputation: 226296
The value float('1e-310') is a denormal number which is outside the usual range of exponents for 53-bit floats (+308 to -308) so it is stored with less precision in order to achieve gradual underflow.
It seems the PostgreSQL has some unresolved issues with denormals: http://archives.postgresql.org/pgsql-hackers/2011-06/msg00885.php
For values near zero, consider rounding them prior to storage in the DB:
>>> round(float('1e-302'), 308)
1e-302
>>> round(float('1e-310'), 308)
0.0
Upvotes: 8