So, here is it, converting from varbinary(8) to 8 byte float:
DECLARE @BinaryFloat AS VARBINARY(8); SET @BinaryFloat = 0x3FF199999999999A; -- Binary representation for 1.1 SELECT SIGN(CAST(@BinaryFloat AS BIGINT)) * (1.0 + (CAST(@BinaryFloat AS BIGINT) & 0x000FFFFFFFFFFFFF) * POWER(CAST(2 AS FLOAT), -52)) * POWER(CAST(2 AS FLOAT), (CAST(@BinaryFloat AS BIGINT) & 0x7ff0000000000000) / 0x0010000000000000 - 1023) -- Returns 1.1
And converting from varbinary(4) to 4 byte float:
DECLARE @BinaryFloat AS VARBINARY(4); SET @BinaryFloat = 0x3FC00000; -- Binary representation for 1.5 SELECT SIGN(CAST(@BinaryFloat AS INT)) * (1.0 + (CAST(@BinaryFloat AS INT) & 0x007FFFFF) * POWER(CAST(2 AS REAL), -23)) * POWER(CAST(2 AS REAL), (CAST(@BinaryFloat AS INT) & 0x7f800000) / 0x00800000 - 127) -- Returns 1.5Hope this helps and saves someone some time.
BTW, anyone knows why casting from varbinary to float is not supported in SQL Server?
Thanks for this piece of code it really helped!
ReplyDeleteI have used this piece of code for years, and it has bee great - thanks!
ReplyDeleteBut... Do you know how to go the other way?
Amazing piece of code!!
ReplyDeleteThis peace of code is pure art.
ReplyDeleteIn my case, binary data used different endianess. Following code change also endianess and pick data from the middle of binary data.
DECLARE @start
SET @start = 828
select
SIGN(CAST(cast(reverse(substring(bd.BinaryData,@start,8)) as binary(8)) AS BIGINT))
* (1.0 + (CAST(cast(reverse(substring(bd.BinaryData,@start,8)) as binary(8)) AS BIGINT) & 0x000FFFFFFFFFFFFF) * POWER(CAST(2 AS FLOAT), -52))
* POWER(CAST(2 AS FLOAT), (CAST(cast(reverse(substring(bd.BinaryData,@start,8)) as binary(8)) AS BIGINT) & 0x7ff0000000000000) / 0x0010000000000000 - 1023) as 'DataValue'
from binarydata bd with (nolock)