首先,我知道如果我有一台8位计算机,它只能处理8位数字,但不能超过8位,但是我知道仍然可以表示16位数字甚至32,64,128-通过在ram中分配更多的内存来获得位数。但是为了简单起见,我们仅以16位数字为例。
假设我们在ram中有一个16位数字,如下所示:
12 34 <-- That's Hexadecimal btw
让我们也以二进制形式编写它,以防万一您偏爱二进制形式:
00010010 00110100 <-- Binary
&
4660 in decimal
现在,我们知道计算机无法将这个大数字(4660)理解为一个数字,因为计算机只能理解8位数字,最高只能达到255。因此右侧的字节将保持不变:
00110100 <-- 52 in decimal
但左字节:
00010010 <-- would be 18 if it was the byte on the right,
but since it is on the left, it means that its
4608
所以我的问题是,如果计算机只能理解小于255的数字,那么计算机如何读取第二个字节为4608,然后如何将这两个字节解释为单个数字(4660)?
谢谢,如果您感到困惑,请随时在评论中问我。我说得越清楚越好。
好吧,这是比硬件体系结构更多的编程问题,因为在您的测试用例中,CPU仅执行8位操作,而对16位则一无所知。您的示例是:在8位ALU上进行16位算术运算,通常是通过将数字的高半部分和低半部分拆分(然后将其相加)来完成的。这可以通过更多的方式来完成,例如以下几种(使用C ++):
转移
const int _h=0; // MSB location
const int _l=1; // LSB location
BYTE h,l; // 8 bit halves
WORD hl; // 16 bit value
h=((BYTE*)(&hl))[_h];
l=((BYTE*)(&hl))[_l];
// here do your 8bit stuff on h,l
((BYTE*)(&hl))[_h]=h;
((BYTE*)(&hl))[_l]=l;
您需要从8bit / 16bit的“寄存器”副本中复制或复制,这很慢,但有时可以减轻麻烦。
指针
const int _h=0; // MSB location
const int _l=1; // LSB location
WORD hl; // 16 bit value
BYTE *h=((BYTE*)(&hl))+_h;
BYTE *l=((BYTE*)(&hl))+_l;
// here do your 8bit stuff on *h,*l or h[0],l[0]
你不需要复制任何东西,但使用指针访问*h,*l
代替h,l
。指针初始化仅完成一次。
联盟
const int _h=0; // MSB location
const int _l=1; // LSB location
union reg16
{
WORD dw; // 16 bit value
BYTE db[2]; // 8 bit values
} a;
// here do your 8bit stuff on a.db[_h],a.db[_l]
与#2相同,但形式更易于管理
CPU 8/16位寄存器
即使是8位CPU,通常也可以通过一半或全部寄存器访问16位寄存器。例如,在Z80上,您AF,BC,DE,HL,PC,SP
还可以通过其半寄存器直接访问其中的大多数。因此,有使用说明的说明hl
,也有h,l
单独使用说明的说明。在x86上它是相同的,例如:
mov AX,1234h
与以下内容相同(除了计时和可能的代码长度):
mov AH,12h
mov AL,34h
简而言之,这就是8/16位之间的转换,但我想您是在询问有关如何完成操作的更多信息。这可以通过使用Carry标志来完成(可悲的是,大多数高级语言都缺少汇编器)。例如,在8位ALU(x86体系结构)上进行16位加法是这样的:
// ax=ax+bx
add al,bl
adc ah,bh
因此,首先添加最低的BYTE,然后添加最高的+ Carry。有关更多信息,请参见:
有关如何实现其他操作的更多信息,请参见关于bignum算术的任何实现。
[Edit1]
这是一个仅用8位算术即可打印16位数字的小型C ++示例。您可以将8位ALU用作构建块,以进行N*8
16位操作的相同方式进行位操作...
//---------------------------------------------------------------------------
// unsigned 8 bit ALU in C++
//---------------------------------------------------------------------------
BYTE cy; // carry flag cy = { 0,1 }
void inc(BYTE &a); // a++
void dec(BYTE &a); // a--
BYTE add(BYTE a,BYTE b); // = a+b
BYTE adc(BYTE a,BYTE b); // = a+b+cy
BYTE sub(BYTE a,BYTE b); // = a-b
BYTE sbc(BYTE a,BYTE b); // = a-b-cy
void mul(BYTE &h,BYTE &l,BYTE a,BYTE b); // (h,l) = a/b
void div(BYTE &h,BYTE &l,BYTE &r,BYTE ah,BYTE al,BYTE b); // (h,l) = (ah,al)/b ; r = (ah,al)%b
//---------------------------------------------------------------------------
void inc(BYTE &a) { if (a==0xFF) cy=1; else cy=0; a++; }
void dec(BYTE &a) { if (a==0x00) cy=1; else cy=0; a--; }
BYTE add(BYTE a,BYTE b)
{
BYTE c=a+b;
cy=DWORD(((a &1)+(b &1) )>>1);
cy=DWORD(((a>>1)+(b>>1)+cy)>>7);
return c;
}
BYTE adc(BYTE a,BYTE b)
{
BYTE c=a+b+cy;
cy=DWORD(((a &1)+(b &1)+cy)>>1);
cy=DWORD(((a>>1)+(b>>1)+cy)>>7);
return c;
}
BYTE sub(BYTE a,BYTE b)
{
BYTE c=a-b;
if (a<b) cy=1; else cy=0;
return c;
}
BYTE sbc(BYTE a,BYTE b)
{
BYTE c=a-b-cy;
if (cy) { if (a<=b) cy=1; else cy=0; }
else { if (a< b) cy=1; else cy=0; }
return c;
}
void mul(BYTE &h,BYTE &l,BYTE a,BYTE b)
{
BYTE ah,al;
h=0; l=0; ah=0; al=a;
if ((a==0)||(b==0)) return;
// long binary multiplication
for (;b;b>>=1)
{
if (BYTE(b&1))
{
l=add(l,al); // (h,l)+=(ah,al)
h=adc(h,ah);
}
al=add(al,al); // (ah,al)<<=1
ah=adc(ah,ah);
}
}
void div(BYTE &ch,BYTE &cl,BYTE &r,BYTE ah,BYTE al,BYTE b)
{
BYTE bh,bl,sh,dh,dl,h,l;
// init
bh=0; bl=b; sh=0; // (bh,bl) = b<<sh so it is >= (ah,al) without overflow
ch=0; cl=0; r=0; // results = 0
dh=0; dl=1; // (dh,dl) = 1<<sh
if (!b) return; // division by zero error
if ((!ah)&&(!al)) return; // division of zero
for (;bh<128;)
{
if (( ah)&&(bh>=ah)) break;
if ((!ah)&&(bl>=al)) break;
bl=add(bl,bl);
bh=adc(bh,bh);
dl=add(dl,dl);
dh=adc(dh,dh);
sh++;
}
// long binary division
for (;;)
{
l=sub(al,bl); // (h,l) = (ah,al)-(bh,bl)
h=sbc(ah,bh);
if (cy==0) // no overflow
{
al=l; ah=h;
cl=add(cl,dl); // increment result by (dh,dl)
ch=adc(ch,dh);
}
else{ // overflow -> shoft right
if (sh==0) break;
sh--;
bl>>=1; // (bh,bl) >>= 1
if (BYTE(bh&1)) bl|=128;
bh>>=1;
dl>>=1; // (dh,dl) >>= 1
if (BYTE(dh&1)) dl|=128;
dh>>=1;
}
}
r=al; // remainder (low 8bit)
}
//---------------------------------------------------------------------------
// print 16bit dec with 8bit arithmetics
//---------------------------------------------------------------------------
AnsiString prn16(BYTE h,BYTE l)
{
AnsiString s="";
BYTE r; int i,j; char c;
// divide by 10 and print the remainders
for (;;)
{
if ((!h)&&(!l)) break;
div(h,l,r,h,l,10); // (h,l)=(h,l)/10; r=(h,l)%10;
s+=char('0'+r); // add digit to text
}
if (s=="") s="0";
// reverse order
i=1; j=s.Length();
for (;i<j;i++,j--) { c=s[i]; s[i]=s[j]; s[j]=c; }
return s;
}
//---------------------------------------------------------------------------
我使用VCL AnsiString
进行文本存储,您可以将其更改为字符串,甚至char[]
改为字符串。您需要除以BYTE的整数,然后将整数除。查看该div
功能的工作原理。此处为264打印的最低有效位的示例264%10
...
a = 264 = 00000001 00001000 bin
b = 10 = 00000000 00001010 bin
d = 1 = 00000000 00000001 bin
// apply shift sh so b>=a
a = 00000001 00001000 bin
b = 00000001 01000000 bin
d = 00000000 00100000 bin
sh = 5
// a-=b c+=d while a>=b
// a<b already so no change
a = 00000001 00001000 bin b = 00000001 01000000 bin c = 00000000 00000000 bin d = 00000000 00100000 bin
// shift right
b = 00000000 10100000 bin d = 00000000 00010000 bin sh = 4
// a-=b c+=d while a>=b
a = 00000000 01101000 bin c = 00000000 00010000 bin
// shift right
b = 00000000 01010000 bin d = 00000000 00001000 bin sh = 3
// a-=b c+=d while a>=b
a = 00000000 00011000 bin c = 00000000 00011000 bin
// shift right
b = 00000000 00101000 bin d = 00000000 00000100 bin sh = 2
b = 00000000 00010100 bin d = 00000000 00000010 bin sh = 1
// a-=b c+=d while a>=b
a = 00000000 00000100 bin c = 00000000 00011010 bin
// shift right
b = 00000000 00001010 bin d = 00000000 00000001 bin sh = 0
// a<b so stop a is remainder -> digit = 4
//now a=c and divide again from the start to get next digit ...
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句