I have a particular table with a column data type of float(53), non null. According to the Microsoft Documentation, the smallest value above 0 that can be stored in this data type is is 2.23E-308. However, I am able to store a value much smaller, as small as 4.94065645841247E-324. See the following image of proof that SQL server can store and retrieve a value outside the range specified in the documentation:
When I run a query such as the following:
select 4.7E-309
SQL Server says: Warning: the floating point value '4.7E-309' is too small. It will be interpreted as 0.
The value inserted in the screenshot was inserted via the C++ ADO interface using record binding.
I have a few questions:
Why does SQL server handle values outside the range specified in the documentation?
Similarly, why does SQL Server issue a warning when an "out of range" value is in the query, when clearly the database can store values out of that range?
How are floating points stored on SQL database tables, and are there any SQL server settings that would strictly enforce the range on one SQL server as opposed to another?
I'm trying to troubleshoot an issue where an ADO record binding was (possibly) rejected due to the value being out of range, however all my test to reproduce the issue (on a different SQL server instance) show that SQL accepts values much beyond the limits specified in the documentation. Any information on how floating points are stored and handled in SQL (especially with relation to something like .NET or C++) would be much appreciated.
I have tested this with both SQL server 2005 and 2008 with the same results.
Best Answer
I suspect this is a validation error (ie. a bug). Wouldn't be the first, specially in 2005-2008 (there was a big data purity fixes push in 2012 I think). I suspect that a
DBCC CHECKDB WITH DATA_PURITY
will complain about the value.SQL Server stores floats as IEEE 754, same way as .Net and C++ represents them. 64 bit can represent values way above and bellow the 2.23E-308, as you already found out about 4.94065645841247E-324 (ie. 0x0000000000000001 interpreted as a float). But such values fail another IEE754 requirement, namely reproducibility:
This requirement places the limit at documented numbers:
The fact that ADO binding allows basically any combination of bits to be passed as the value and the SQL Server accepts the binding buffer w/o validation results in the behavior you noticed. Technically, the data you inserted this way is a corruption. Again, I suspect that a) newer versions of the engine validate the buffer before write (in other words they catch the invalid value) and b)
WITH DATA_PURITY
check will report the problem (even on 2005/2008/R2 versions).