将十进制/整数转换为二进制 - 它以何种方式工作? [英] Converting decimal/integer to binary - how and why it works the way it does?

查看:118
本文介绍了将十进制/整数转换为二进制 - 它以何种方式工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如已经在大卫的回答中所提到的那样这里,我真的很感兴趣这个函数如何工作,因为如果将结果长度从32到16或8更改,似乎不能得到相同的(正确的)值。



我使用函数

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

哪里工作很好。 (1作为000 .... 001,2作为000 .... 010,3作为000 ... 011,等等)返回。



但是,由于我只需要8个字符长字符串结果,所以我将一个函数中的数字改为8,以得到:

 函数IntToBin(Value:LongWord):string; 
var
i:整数;
begin
SetLength(Result,8);
for i:= 1 to 8 do begin
if((value shl(i-1))shr 7)= 0 then begin
结果[i]:='0'
end else begin
结果[i]:='1';
结束
结束
结束

但是我收到的结果如下:

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

类似于16而不是8。



尝试将LongWord更改为整数,字节也是,但得到相同的结果。



所以...嗯...我在这里缺少什么,不明白? :/



PS:请求学习目的,在第一个函数结束时用Copy(Result,25,8)解决了我的情况,因为需要8个字符长字符串通过,但我真的想了解发生了什么...:)



谢谢

解决方案

代码中的左移是将您感兴趣的位移到数据类型的左边缘。通过这样做,左边的所有位都被移出结尾并丢失。那么当你再次向右移动时,我们一直转向另一端。结果是0或1.



但是,您的数据类型仍为32位,因此您的转换不够远。你没有得到目标位左侧的所有位都落到最后。所以当你转向右边时他们会返回。



为了使您的代码工作,您需要这样:

  function IntToBinLowByte (Value:LongWord):string; 
var
i:整数;
begin
SetLength(Result,8);
for i:= 1 to 8 do begin
if((value shl(24 + i-1))shr 31)= 0 then begin
Result [i]:='0'
end else begin
结果[i]:='1';
结束
结束
结束

相对于原始版本,可能更容易理解的版本将如下所示: / p>

  function IntToBinLowByte(Value:LongWord):string; 
var
i:整数;
begin
SetLength(Result,8);
for i:= 25 to 32 do begin
if((value shl(i-1))shr 31)= 0 then begin
结果[i-24]:='0'
end else begin
结果[i-24]:='1';
结束
结束
结束然而,坦白说,在单个字节上操作是更好的方法,但是,b
$ /我发现这个双重变化有点模糊。我会使用一个单一的位和一个掩码。如下:

  function IntToBinByte(Value:Byte):string; 
var
i:整数;
begin
SetLength(Result,8);
for i:= 1到8 do begin
if(Value shr(8-i))and 1 = 0 then begin
Result [i]:='0'
结果else begin
结果[i]:='1';
结束
结束
结束

并将其称为

  str:= IntToBinByte(Value和$ ff); 

假设是一个32位数据类型。显然,如果它已经是一个字节,那么你不需要按位



而且,原来的32位功能会在这个谦虚的意见中看起来更好。






此答案的早期版本以下错误尝试解决问题:

  function IntToBinByte(Value:Byte):string; 
var
i:整数;
begin
SetLength(Result,8);
for i:= 1 to 8 do begin
if((value shl(i-1))shr 7)= 0 then begin
结果[i]:='0'
end else begin
结果[i]:='1';
结束
结束
结束

问题是即使 Value 是8位类型,按位操作在32位寄存器中执行。因此,当执行右移时,左移位到位数> 7的位返回。您可以通过掩盖那些意图脱落的位来轻松解决这个问题。如下:

  function IntToBinByte(Value:Byte):string; 
var
i:整数;
begin
SetLength(Result,8);
for i:= 1 to 8 do begin
if(Value shl(i-1)and $ ff)shr 7 = 0 then begin
Result [i]:='0'
end else begin
结果[i]:='1';
结束
结束
结束

这段代码真的很复杂,我不推荐任何人使用它。在我看来,最好的版本是我的答案中的第三个代码块。


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

解决方案

The left shift in the code is meant to shift the bit you are interested in to the very left hand edge of the data type. By doing so, all bits to the left are shifted off the end and lost. Then when you shift right again, we shift all the way to the other end. The result is either 0 or 1.

However, your data type is still 32 bits, and so you are not shifting far enough. You are not getting all the bits to the left of the target bit to fall off the end. And so they return when you shift to the right.

To make your code work you need this:

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

A version that might be easier to understand, in relation to the original, would be like this:

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

Frankly however it is better to operate on a single byte. And I find this double shifting to be a little obscure. I'd use a single shift and a bit mask. Like this:

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

And call it like this

str := IntToBinByte(Value and $ff);

assuming that Value is a 32 bit data type. Obviously if it is already a Byte then you don't need the bitwise and.

And the original 32 bit function would read better like this, in my humble opinion.


Earlier versions of this answer had the following incorrect attempt to solve the problem:

function IntToBinByte(Value: Byte): 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;

The problem is that, even though Value is an 8 bit type, the bitwise operations are performed in 32 bit registers. So the bits that are left shifted to bit number >7 return when the right shift is performed. You can fix this easily enough by masking out those bits that are meant to fall off the end. Like this:

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

This code is really convoluted I don't recommend that anyone ever uses it. The best version, in my opinion, is the third block of code in my answer.

这篇关于将十进制/整数转换为二进制 - 它以何种方式工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆