Convert Delphi Real48 to C # double

I need to be able to convert from Delphi Real48 to C # double.

I have bytes that I need to convert, but I'm looking for an elegant solution. to the problem.

Has anyone had to do this before?

I need to do a conversion in C #

Thanks in advance

+6
double c # delphi
source share
5 answers

I did some hunting around, and I found C ++ code to complete the task, converted it, and seemed to give the correct answer ... damn if I understood everything: S

private static double Real48ToDouble(byte[] real48) { if (real48[0] == 0) return 0.0; // Null exponent = 0 double exponent = real48[0] - 129.0; double mantissa = 0.0; for (int i = 1; i < 5; i++) // loop through bytes 1-4 { mantissa += real48[i]; mantissa *= 0.00390625; // mantissa /= 256 } mantissa += (real48[5] & 0x7F); mantissa *= 0.0078125; // mantissa /= 128 mantissa += 1.0; if ((real48[5] & 0x80) == 0x80) // Sign bit check mantissa = -mantissa; return mantissa * Math.Pow(2.0, exponent); } 

If someone can explain this, it would be great: D

+8
source share
 static double GetDoubleFromBytes(byte[] bytes) { var real48 = new long[6]; real48[0] = bytes[0]; real48[1] = bytes[1]; real48[2] = bytes[2]; real48[3] = bytes[3]; real48[4] = bytes[4]; real48[5] = bytes[5]; long sign = (real48[0] & 0x80) >> 7; long significand = ((real48[0] % 0x80) << 32) + (real48[1] << 24) + (real48[2] << 16) + (real48[3] << 8) + (real48[4]); long exponent = bytes[5]; if (exponent == 0) { return 0.0; } exponent += 894; long bits = (sign << 63) + (exponent << 52) + (significand << 13); return BitConverter.Int64BitsToDouble(bits); } 
+3
source share

Appreciate that this is an old post, but the following may also be useful for those who want to do this in T-SQL (as I was).

 IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[ifn_HexReal48ToFloat]') AND type in (N'FN', N'IF', N'TF', N'FS', N'FT')) drop function [dbo].[ifn_HexReal48ToFloat] go SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO create function [dbo].[ifn_HexReal48ToFloat] ( @strRawHexBinary char(12), -- NOTE. Do not include the leading 0x @bitReverseBytes bit ) RETURNS FLOAT AS BEGIN -- Reverse bytes if required -- eg 3FF4 0000 0000 is stored as -- 0000 0000 F43F declare @strNewValue varchar(12) if @bitReverseBytes = 1 begin set @strNewValue='' declare @intCounter int set @intCounter = 6 while @intCounter>=0 begin set @strNewValue = @strNewValue + substring(@strRawHexBinary, (@intCounter * 2) + 1,2) set @intCounter = @intCounter - 1 end end -- Convert the raw string into a binary declare @binBinaryFloat binary(6) set @binBinaryFloat = convert(binary(6),'0x' + isnull(@strNewValue, @strRawHexBinary),1) -- Based on original hex to float conversion at http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=81849 -- and storage format documented at -- http://docs.embarcadero.com/products/rad_studio/delphiAndcpp2009/HelpUpdate2/EN/html/devcommon/internaldataformats_xml.html -- Where, counting from the left -- Sign = bit 1 -- Exponent = bits 41 - 48 with a bias of 129 -- Fraction = bits 2 - 40 return SIGN ( CAST(@binBinaryFloat AS BIGINT) ) * -- Fraction part. 39 bits. From left 2 - 40. ( 1.0 + (CAST(@binBinaryFloat AS BIGINT) & 0x7FFFFFFFFF00) * POWER(CAST(2 AS FLOAT), -47) ) * -- Exponent part. 8 bits. From left bits 41 -48 POWER ( CAST(2 AS FLOAT), ( CAST(@binBinaryFloat AS BIGINT) & 0xff - 129 ) ) end 

the confirmation

0.125 is 0x0000 0000 007E (or 0x 7E00 0000 0000 in reverse order)

 select dbo.ifn_HexReal48ToFloat('00000000007E', 0) select dbo.ifn_HexReal48ToFloat('7E0000000000', 1) 

The input is char12 because I had to extract the binary from the middle of two other larger binary fields and shunt them together if it was already char12. It is easy enough to switch to binary (6) input if you do not need to do any manipulations in advance.

As an aside, in the script that I am implementing, the T-SQL variant exceeded the C # CLR code, so the C # code above might be better. Although it’s not always possible to use the CLR code in SQL Server, if you then may need to. For more information, the article http://www.simple-talk.com/sql/t-sql-programming/clr-performance-testing/ makes some depth measurements that show some significant differences between T-SQL and CLR.

+2
source share

I tested this and found an error (as others have noticed) with negative values. Here is my verified version of the code. I tested this with 120,530 different random values ​​from 11,400,000.00 to -2,000,000.00

  //This seems to be the layout of the Real48 bits where //E = Exponent //S = Sign bit //F = Fraction //EEEEEEEE FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF SFFFFFFF //12345678 12345678 12345678 12345678 12345678 12345678 Double exponentbase = 129d; // The exponent is offest by 129 Double exponent = real48[0] - exponentbase; // deduct the offest. // Calculate the mantissa Double mantissa = 0.0; Double value = 1.0; // For Each Byte. for (int iByte = 5; iByte >= 1; iByte--) { int startbit = 7; if (iByte == 5) { startbit = 6; } //skip the sign bit. //For Each Bit for (int iBit = startbit; iBit >= 0; iBit--) { value = value / 2;// Each bit is worth half the next bit but we're going backwards. if (((real48[iByte] >> iBit) & 1) == 1) //if this bit is set. { mantissa += value; // add the value. } } } if (mantissa == 1.0 && real48[0] == 0) // Test for null value return 0.0; double result; result = (1 + mantissa) * Math.Pow(2.0, exponent); if ((real48[5] & 0x80) == 0x80) // Sign bit check result = -result; return result; 
+1
source share

I changed the code you posted to a more readable format so you can see how it works:

  Double exponentbase = 129d; Double exponent = real48[0] - exponentbase; // The exponent is offest so deduct the base. // Now Calculate the mantissa Double mantissa = 0.0; Double value = 1.0; // For Each Byte. for (int i = 5; i >= 1; i--) { int startbit = 7; if (i == 5) { startbit = 6; } //skip the sign bit. //For Each Bit for (int j = startbit; j >= 0; j--) { value = value / 2;// Each bit is worth half the next bit but we're going backwards. if (((real48[i] >> j) & 1) == 1) //if this bit is set. { mantissa += value; // add the value. } } } if (mantissa == 1.0 && real48[0] == 0) // Test for null value return 0.0; if ((real48[5] & 0x80) == 1) // Sign bit check mantissa = -mantissa; return (1 + mantissa) * Math.Pow(2.0, exponent); 
0
source share

All Articles