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
1.1k views
in Technique[技术] by (71.8m points)

delphi - Converting decimal/integer to binary - how and why it works the way it does?

As already asked David in a comment of an answer here, I'm really interested on how this function works, since I can't seem to get the same (correct) values if changing result length from 32 to 16 or 8.

I used function

function IntToBin(Value: LongWord): string;
var
  i: Integer;
begin
  SetLength(Result, 32);
  for i := 1 to 32 do begin
    if ((Value shl (i-1)) shr 31) = 0 then begin
      Result[i] := '0'
    end else begin
      Result[i] := '1';
    end;
  end;
end;

which somehow works just fine. (1 is returned as 000....001, 2 as 000....010, 3 as 000...011, etc...).

However, since I only needed 8 chars long string result, I changed the numbers in a function to 8 to get this:

function IntToBin(Value: LongWord): string;
var
  i: Integer;
begin
  SetLength(Result, 8);
  for i := 1 to 8 do begin
    if ((Value shl (i-1)) shr 7) = 0 then begin
      Result[i] := '0'
    end else begin
      Result[i] := '1';
    end;
  end;
end;

but I get results as they follow:

 1: 00000001
 2: 00000011
 3: 00000011
 4: 00000111
 5: 00000111
 6: 00000111
 7: 00000111
 8: 00001111
 9: 00001111
10: 00001111
11: 00001111
12: 00001111

Kinda same for 16 instead of 8.

Tried to change LongWord to Integer and Byte as well, but got the same results.

So... hm... what am I missing here, and don't understand? :/

PS: Asking in learning purposes, solved my case with Copy(Result, 25, 8) at the end of the first function, because needed 8 chars long string passed, but I really want to understand what's going on... :)

Thanks

See Question&Answers more detail:os

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

1 Reply

0 votes
by (71.8m points)

As David so clearly answered, your bitshifting was either to short, or the operand was implicitly expanded by the compiler.

If performance is important, here is a routine that is faster than the one David presented.

function IntToBinByte(Value: Byte): String; 
var 
  i: Integer; 
  pStr: PChar; 
begin 
  SetLength( Result,8); 
  pStr := PChar(Pointer(Result));  // Get a pointer to the string
  for i := 7 downto 0 do begin 
    pStr[i] := Char(Ord('0') + ((Value shr (7 - i)) and 1)); 
  end; 
end;

By working with a pointer, you avoid protecting the string every time it is updated. The protection is not needed here, since no other part of your program can access the Result string.

The string protection scheme in Delphi is called Copy On Write (COW), and works by having a reference counter that keeps count on every instance that is referencing the string. When a string is written on and the reference count is greater than 1, a new string is allocated for writing.


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

...