我需要能够从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