我需要能夠從Delphi Real48轉換爲C#double。將Delphi Real48轉換爲C#double
我有我需要轉換的字節,但我正在尋找一個優雅的解決方案。解決問題。
那裏的任何人都必須這樣做嗎?
,我需要做的轉換在C#
在此先感謝
我需要能夠從Delphi Real48轉換爲C#double。將Delphi Real48轉換爲C#double
我有我需要轉換的字節,但我正在尋找一個優雅的解決方案。解決問題。
那裏的任何人都必須這樣做嗎?
,我需要做的轉換在C#
在此先感謝
我身邊做了一些狩獵和我發現了一些C++代碼來完成這項工作,將其轉換並似乎給予正確的答案...如果我明白這一切雖然可惡: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);
}
如果有人能解釋一下這將是巨大的:d
字節1到5以科學計數法表示數字的小數部分:1.x * 2^e'。尾數是1.x。 * for *循環和下面兩行生成* x *。假設字節1是0xa5。在二進制中,這是10100101.添加到'尾數'得到'尾數== 0xa5'。然後*將這些字節向下移動到小數部分以獲得二進制值0.10100101。移位8除以256.重複字節2到4.字節5是特殊的,因爲我們只需要7位 - 第八位是符號位 - 所以用128來代替。最後加1,因爲那部分是* implicit *(不存儲在任何地方)。 – 2010-03-24 19:45:41
字節0是指數。這是一個無符號數字,但它有129偏高,所以首先要做的是正確的偏見。正如在前面的評論中提到的那樣,數字的形式是'1.x * 2^e',其中'1.x'存儲在'尾數'中,'e'存儲在'exponent'中。最後一行代碼簡單地將該值計算爲double。 – 2010-03-24 19:49:49
對未來讀者的注意:我相當確信這段代碼有錯誤。首先,它忽略了real48的字節值[4]。建議謹慎。 – 2011-02-05 18:39:50
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);
}
從Delphi基礎知識:「Real48:Obsolete - 具有最高容量和精度的浮點類型。」在Delphi的擴展版本(10字節) – 2010-03-24 11:00:01
@Darin的現代版本中,恐怕這似乎沒有給出正確的答案 – 2010-03-24 11:10:22
事實上,似乎有什麼問題。我會再檢查一次。 – 2010-03-24 11:18:02
我已經改變了你已經張貼到一個更可讀的格式代碼,以便你可以看到它是如何工作的:
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);
此代碼至少引入一個錯誤。你忘了用負面的輸入來測試它。 – 2010-03-24 19:34:37
他正等着你爲他測試Rob。謝謝! – Pauk 2010-03-25 10:34:06
明白這是一個古老的職位,但也可以進行以下爲那些尋找有用在T-SQL(我當時)中這樣做。
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
-- e.g. 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
確認
0.125是0X 0000 0000 007E(或0X 7E00 0000 0000反向)
select dbo.ifn_HexReal48ToFloat('00000000007E', 0)
select dbo.ifn_HexReal48ToFloat('7E0000000000', 1)
輸入是一個char12如我不得不提取的2中間的二進制其他更大的二進制字段並將它們分開,所以它已經作爲char12。如果事先不需要做任何操作,就可以很容易地更改爲二進制(6)輸入。另外,在我實現的場景中,T-SQL變體的性能優於C#CLR代碼,因此上面的C#代碼可能會更好。雖然不是到處都允許CLR代碼到SQL Server,如果你可以,那麼也許你應該。欲瞭解更多背景信息,http://www.simple-talk.com/sql/t-sql-programming/clr-performance-testing/的文章做了一些深入的測量,它顯示了T-SQL和CLR之間的一些顯着差異。
我一直在測試這個,並發現一個錯誤(正如其他人已經注意到)與負值。這是我測試過的代碼版本。我測試了120,530個不同的隨機值,範圍從11,400,000.00到-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;
人們仍在使用Real48?爲什麼?! – 2010-03-24 10:44:11
你需要將它們轉換成什麼?在Delphi程序中? – 2010-03-24 10:45:29
@Ignacio:想到向後兼容性。 – 2010-03-24 10:46:19