Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
268 views
in Technique[技术] by (71.8m points)

Pls correct these functions of float number (type: double) under binary form in delphi

I've written 2 functions to convert a float number into/from binary, but the result is incorrect. Please help me to find its bug. (I found some FAQ for this topic, but they was written for 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;

Using

temp: string;
f: double;

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

I wonder the variable f should be 3.14... but..??? Please help me correct them. Thanks

question from:https://stackoverflow.com/questions/65930207/pls-correct-these-functions-of-float-number-type-double-under-binary-form-in

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Your problem is essentially the mask computation. You do 1 shl I which gives a 32 bit value. You must do UInt64(1) shl I to get a 64 bit value.

Here is your code fixed:

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;

And if you want to test:

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;

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...