请在delphi中以二进制形式更正浮点数类型:double的这些函数

问题描述

我已经编写了 2 个函数来将浮点数转换为二进制数,但结果不正确。请帮我找到它的错误。 (我找到了一些关于这个主题的 FAQ,但它们是为 C/C++ 编写的)

function MyFloatToBin(d: double): String;
var
  d_ptr: ^Int64;
  d_str: string;
  i: Integer;
  ch: char;
begin
  d_ptr:= @d;
  d_str:= '';
  for i:= 0 to 63 do begin
    if (d_ptr^ and (1 shl i)) > 0 then
      ch:= '1'
    else
      ch:= '0';
    d_str:= d_str + ch;
  end;
  Result:= 'F' + d_str;
end;

function MyBinToFloat: Double;
var
  d_str: String;
  i64: Int64;
  d_ptr: ^double;
  i,len: Integer;
begin
  d_str:= pop;
  len:= length(d_str);
  if (pos('F',d_str) <> 1)and(len <> 65) then begin
    push(d_str);
    exit;
  end;
  i64:= 0;
  for i:= 2 to len do
    if d_str[i] = '1' then
      i64:= i64 or (1 shl (i - 2));
  d_ptr:= @i64;
  Result:= d_ptr^;
end;

使用

temp: string;
f: double;

temp:= MyFloatToBin(pi);//pi = 3.14....
f:= MyBinToFloat(temp);//result at f is 0

我想知道变量 f 应该是 3.14...但是...??? 请帮我纠正它们。 谢谢

解决方法

您的问题本质上是掩码计算。你做 1 shl I 这给出了一个 32 位的值。您必须执行 UInt64(1) shl I 才能获得 64 位值。

这是您修复的代码:

function MyFloatToBinString(d: double): String;
var
    VP : ^UInt64;
    I  : Integer;
begin
    VP  := @d;
    Result := 'F';
    for I := 63 downto 0 do begin
        if (VP^ and (UInt64(1) shl I)) <> 0 then
            Result := Result + '1'
        else
            Result := Result + '0';
    end;
end;

function MyBinStringToFlat(S : String) : Double;
var
    V : UInt64;
    I : Integer;
    J : Integer;
begin
    if (Length(S) <> 65) or ((S[1] <> 'F') and (S[1] <> 'f')) then
        raise Exception.Create('Invalid format');

    V := 0;
    for I := 65 downto 2 do begin
        case S[I] of
        '1': V := V or (UInt64(1) shl (65 - I));
        '0': { Nothing to do };
        else
            raise Exception.Create('Invalid format');
        end;
    end;
    Result := PDouble(@V)^;
end;

如果你想测试:

procedure TForm1.Button1Click(Sender: TObject);
var
    V1 : Double;
    V2 : Double;
    S  : String;
begin
    V1 := 3.1416;
    Memo1.Lines.Add(IntToHex(PUInt64(@V1)^));
    S := MyFloatToBinString(V1);
    Memo1.Lines.Add(S);
    V2 := MyBinStringToFlat(S);
    Memo1.Lines.Add(V2.ToString);
end;