MicroTip#5 内存字节转为浮点数
//====================================================================
//MicroTip#5 内存字节转为浮点数
// Test in Delphi6 up2
// Wrtten by SkyJacker 2007.03.22
// QQ Discuss Group: 130970
// 注:本人发布的源码,仅供参考,不保证无Bug。
// 非常欢迎讨论 Code 或 Bug 问题。
// 您出了个优化版本后,别忘了发给我一份啊。谢谢! 我的 QQ: 6705517
//====================================================================
函数需求:内存字节转为浮点数
方法实现:IEEE标准754 或 类型转换
采用方法:IEEE标准754
类型定义:
//4内存字节转为浮点数Single
TByte4 = packed record
F1: Byte;
F2: Byte;
F3: Byte;
F4: Byte; //1-4 由低字节到高字节
end;
//8字节 64 位的浮点数有必要定义一个数组
//注意Btyte8 数组索引小的存放高字节
TByte8 = array[1..64] of Byte; //字节由 高 到 低 便于计算
{
函数功能:将4个内存字节(低位在前,高位在后)转为浮点数 Single
创建人:SkyJacker
创建日期:2006-09-22 14:17:45
修改记录:常量需要优化 bias
函数来历:IEEE标准754:浮点数表示----单精度
单精度:N共32位,其中S占1位,E占8位,M占23位。
公式:n=(-1)^s * 2^e * m
n,s,e,m 分别为N,S,E,M对应的实际数值,而N,S,E,M仅仅是一串二进制位。
S(sign) 表示N的符号位。对应值s满足:n>0时,s=0; n<0时,s=1。
E(exponent) 表示N的指数位,位于S和M之间的若干位。对应值e值也可正可负。
M(mantissa) 表示N的尾数位,恰好,它位于N末尾。M也叫有效数字位(sinificand)、
系数位(coefficient), 甚至被称作“小数”。
}
function ByteToFloat(const Bytes: TByte4): Single;
const
k = 8; //幂位数 Single=8
var
SByte: Byte; //含有符号位的字节
//公式相关
EByte: Byte; //存放幂E
MByte: Byte; //二进制位暂存
n: Single; //结果
s: Integer; //符号位数字表示 +1 -1
e: Integer; //幂值
m: Single; //位数值
//子公式相关
//规格化
bias: Integer; //偏置
En: Integer; //幂的值
i: Integer; //位数 m 23位
begin
//符号相关
SByte := Bytes.F4;
if (SByte and $80) = $00 then
s := 1
else
s := -1;
//初始化取值
EByte := (SByte shl 1) or (Bytes.F3 shr 7); //取8位幂E
bias := Pow(2, (k - 1)) - 1;
En := EByte;
//e := En - bias; //根据是否规格化判断
//是否规格化判断
if EByte = $00 then
begin
{
当E的二进制位全部为0时,N为非规格化形式。此时e,m的计算都非常简单。
此时: e:=1-bias; m=|0.M|
为什么e会等于(1-bias)而不是(-bias),
这主要是为规格化数值、非规格化数值之间的平滑过渡设计的。
}
e := 1 - bias;
m := 0; //m的初始值 非规格化
end
else if EByte = $FF then
begin
{
特殊数值: 当E的二进制位全为1时为特殊数值。
此时,若M的二进制位全为0,则n表示无穷大,
若S为1则为负无穷大,若S为0则为正无穷大;
若M的二进制位不全为0时,表示NaN(Not a Number),
表示这不是一个合法实数或无穷,或者该数未经初始化。
}
{
raise ERangeError.Create(#13 + '浮点数溢出或数据未初始化.' + #13);
Single 1.5 x 10^?5 .. 3.4 x 10^38
}
Result := 0; //防止溢出或未初始化
Exit;
end
else
begin //规格化计算方法
{
当E的二进制位不全为0,也不全为1时,N为规格化形式。
e=|E| - bias
bias=2^(k-1) - 1
k则表示E的位数,
对单精度来说,k=8,则bias=127,
对双精度来说,k=11,则bias=1023。
|E|表示E的二进制序列表示的整数值,例如E为"10000100",则|E|=132,e=132-127=5。
此时e被解释为表示偏置(biased)形式的整数
m=|1.M|
标准规定此时小数点左侧的隐含位为1,那么m=|1.M|。
如M="101",则|1.M|=|1.101|=1.625,即 m=1.625
总公式:n=(-1)^s * 2^e * m
}
e := En - bias;
m := 1; //m的初始值 规格化
end;
//计算m 通过字节移位的方式
MByte := Bytes.F3 shl 1; //去掉1个幂位,即幂位清0
MByte := MByte shr 1; ; //再移回
for I := 7 downto 1 do
begin
m := m + (MByte and $01) / pow(2, I); //2^(-7) + ~ + 2^(-1)
MByte := MByte shr 1;
end;
//后面23-7位数小数不能忽略不计
//第3个尾数字节
MByte := Bytes.F2;
for I := 15 downto 8 do
begin
m := m + (MByte and $01) / pow(2, I); //2^(-17) + ~ + 2^(-8)
MByte := MByte shr 1;
end;
//第4个尾数字节 如果全为0,可以调过
MByte := Bytes.F1;
if MByte <> $00 then
begin
for I := 23 downto 16 do
begin
m := m + (MByte and $01) / pow(2, I); //2^(-23) + ~ + 2^(-16)
MByte := MByte shr 1;
end;
end;
n := s * Power(2, e) * m;
Result := n;
end;
{
函数功能:将8个内存字节(低位在前,高位在后)转为浮点数 Double
创建人:SkyJacker
创建日期:2006-09-22 17:46:58
函数来历:IEEE标准754:浮点数表示----单精度
双精度:N共32位,其中S占1位,E占11位,M占52位。
公式:n=(-1)^s * 2^e * m
//注意Btyte8 数组索引小的存放高字节
}
function ByteToFloat(const Bytes: TByte8): Double;
const
k = 11; //幂位数 Double=11
var
TmpByte: Byte; //临时字节
//公式相关
n: Double; //结果
s: Integer; //符号位数字表示 +1 -1
e: Integer; //幂值
m: Double; //位数值
//子公式相关
//规格化
bias: Integer; //偏置
En: Integer; //幂的值
I: Integer; //位数 m 23位
A: Integer; //3~8个字节
B: Integer; //TBits偏移 从5开始
Bits: TBits; //存放二进制位 E=11 M=52
//判断是否规格化
//Result=$00非规格化 =$FF 特殊数值 其他:规格化
function NormalizedStatus(const Bits: TBits): Byte;
var
I: Integer;
a, b: Integer;
begin
a := 0;
b := 0;
for I := 11 downto 1 do //Error:for I:=Bits.size(=12) downto 1 do
begin
if Bits.Bits[I] then
Inc(b)
else
Inc(a);
end;
if (Bits.Size - 1) = a then //为什么Bits.Size大小变为12
Result := $00
else if (Bits.Size - 1) = b then
Result := $FF
else Result := $01; //规格化
end;
begin
//符号相关
if (Bytes[1] and $80) = $00 then
s := 1
else
s := -1;
bias := pow(2, (k - 1)) - 1;
//整理11位二进制幂值 E
Bits := TBits.Create;
Bits.Size := 11;
TmpByte := Bytes[1];
TmpByte := TmpByte shl 1; //移去符号位
for I := 1 to 7 do
begin
Bits[I] := ((TmpByte and $80) = $80);
TmpByte := TmpByte shl 1;
end;
TmpByte := Bytes[2];
for I := 1 to 4 do
begin
Bits[I + 7] := ((TmpByte and $80) = $80);
TmpByte := TmpByte shl 1;
end;
//求幂值
En := 0;
for I := 11 downto 1 do
begin
if Bits.Bits[12 - I] then
En := En + pow(2, (I - 1));
end;
//e := En - bias; //根据是否规格化判断
TmpByte := NormalizedStatus(Bits);
//是否规格化判断
if TmpByte = $00 then
begin
e := 1 - bias;
m := 0; //m的初始值 非规格化
end
else if TmpByte = $FF then
begin
//特殊数值: 当E的二进制位全为1时为特殊数值。
Result := 0; //防止溢出或未初始化
Exit;
end
else
begin //规格化计算方法
e := En - bias;
m := 1; //m的初始值 规格化
end;
//计算m 通过字节移位的方式
//整理52位尾数二进制M
Bits.Size := 52; //Size自动复值了以前11个值,由于重新赋值,因为不会影响结果。
TmpByte := Bytes[2]; //5~8 bit
TmpByte := TmpByte shl 4;
for I := 1 to 4 do
begin
Bits[I] := ((TmpByte and $80) = $80);
TmpByte := TmpByte shl 1;
end;
//3到8个字节位存入Bits
B := 5;
for A := 3 to 8 do
begin
TmpByte := Bytes[A];
for I := 1 to 8 do
begin
Bits[B] := ((TmpByte and $80) = $80);
TmpByte := TmpByte shl 1;
Inc(B);
end;
end;
//求m值
for I := 1 to 52 do
begin
if Bits.Bits[I] then
m := m + 1 / power(2, I);
end;
n := s * Power(2, e) * m;
Bits.Free;
Result := n;
end;
New:
写了个小程序,有兴趣可以测试一下(Exe + Source)。
[ 本帖最后由 skyjacker 于 2007-3-22 22:59 编辑 ]
Attachment:
[Test Demo]
FloatAsciiEx.rar (2007-3-22 22:40, 184.42 K)
Download count 526, Reading Access 1
|