共有回帖数  0  个 
	 
	
	
	
     
          
          
               
				
			 
				
					 
 
            
				   - 
						
						
							 
									在机器中模拟乘、除法的运算操作(这里没有关于除法的部分) 
因为最近醉心于研究电子电路,写这个是突然间的兴趣所至。 
同时也可以让想了解机器运行的本质的人做参考。 
做为计算机,它和数学思维密切相关。 
这里有几个算式: 
[b代表2进制] 
10     =   1010b  
10 * 2 =  10100b 
10 * 3 =  11110b 
10 * 4 = 101000b 
首先分析: 
(分析过程中全以无符号数做分析对象.2进制数做操作对象) 
1、每左移一位等价于乘2,右移一位等价于除2; 
2、可以将移位(等价于乘2)的动作应用到更广的范围(乘与2以上的数); 
           
      分析和验证: 
          (13 * 27) 
          13 =  1101 
          27 = 11011 
      先通过查看2进制位的标志来分析27 
          [27 = 11011]          
      因为数中: 
          [11011] 
               ^bit 0 = 1 
          [11011] 
              ^ bit 1 = 1  
          [11011] 
             ^  bit 2 = 0 
          [11011] 
            ^   bit 3 = 1 
          [11011] 
           ^    bit 4 = 1 
          27这个数里,最高位为bit4,其中bit0.bit1.bit3.bit4为1(逻辑真),bit2为0(逻辑假)。 
          对13*27里根据对应位的值来对乘数(13)进行移位操作。  
          即若bit 1 为真就[左移1次] 若bit 3 为真就[左移3次], 
          每次移位后和前一次移位的结果相加,直到位被检查完为止。 
          另外bit 0 为真时移动0次的结果等于原数,由此可以区别于通常的乘法方式, 
          这里只进行移位操作,可以把每左移一次理解为乘2,这样就可以抽象出算法来。 
          抽象和简化: 
          通过分析可以得到这样一个简单的方法: 
        a*b[n] = (a*2^0 *b[0]) + (a*2^1 *b[1]) + (a*2^2 *b[2]) + (a*2^3 *b[3]) +... + (a*2^n * b[n]) 
          其中b[n]里n是位数,每个b[n]代表1位2进制数。 
           
          这样就可以得到一个具有普遍意义的方法,再此方法上还可以进一步简化和提高效率 
          (如先比较13 27 里那个大,再把大的数当作移位对象,小的数当作移位条件). 
          虽然很简单,但用程序语言来描述也许能让人看得明白些.下面是一段具有和机器特性相似的代码。 
          用c语言描述(只是用于验证、描述,没有实用意义)就是: 
//----------- 
#include stdio.h 
#define ulong unsigned long 
    int main() 
    {   ulong a,b; 
        ulong c,n; 
        ulong t; 
        int i; 
        t = 1; 
        c = 0; 
        n = sizeof(ulong) 3;  //n = sizeof(ulong) * 8        
     
        printf("%s %dn","bit length",n);   //可用位长度(能存储结果的长度) 
        printf("%sn","input:"); 
        scanf("%d %d",&a,&b); 
        printf("%d %s %d %s",a," * ",b," = "); 
        i = 0; 
        for(i;in;i++)        //扫描前面给的位长度,这里是32 
        {        
            if(b&(t  i))    // b and t   (判断该位是否为真(1),有乘法的特性)        
            {   c += a  i;  //a向左移位i次,结果放入c进行累积 
            } 
        } 
        printf("%d",c); 
    } 
//----------- 
在debug里实现的小片段 
------------ 
C:GCCTESTdebug testm1.com                                           
-u100 13a                                                              
0CAE:0100 33C0          XOR     AX,AX                                  
0CAE:0102 A33A01        MOV     [013A],AX                              
0CAE:0105 B81E00        MOV     AX,001E            ;//[十进制]    30                                
0CAE:0108 BBC801        MOV     BX,01C8            ;//[十进制]   456     // 30 * 456                
0CAE:010B 891E3801      MOV     [0138],BX                                                           
0CAE:010F 32C9          XOR     CL,CL                                                               
0CAE:0111 8BD0          MOV     DX,AX              ;//dx 置入  30                                   
0CAE:0113 52            PUSH    DX                                                                  
0CAE:0114 83E201        AND     DX,+01             ;//从这里开始,反复执行   //比较dx最低位是否为0                                                 
0CAE:0117 740A          JZ      0123               ;//为0就跳过处理部分进行下次比较的初始化  
0CAE:0119 D3E3          SHL     BX,CL              ;//对bx中的数左移cl 位                           
0CAE:011B A13A01        MOV     AX,[013A]          ;//上次的结果取给AX                              
0CAE:011E 03C3          ADD     AX,BX              ;//上次的结果和当前结果相加                      
0CAE:0120 A33A01        MOV     [013A],AX          ;//保存这次的结果                                
0CAE:0123 5A            POP     DX                 ;//取出剩余                                      
0CAE:0124 D1EA          SHR     DX,1               ;//右移1位         
0CAE:0126 FEC1          INC     CL                 ;//当前对应位                    
0CAE:0128 83FA00        CMP     DX,+00             ;//比较dx是否为0                     
0CAE:012B 7607          JBE     0134               ;//小于等于0就跳到结尾                    
0CAE:012D 8B1E3801      MOV     BX,[0138]                              
0CAE:0131 52            PUSH    DX                                     
0CAE:0132 EBE0          JMP     0114                                   
0CAE:0134 A13A01        MOV     AX,[013A]          ;//结束前把结果取给AX[这句可以省略]                    
0CAE:0137 C3            RET                                            
0CAE:0138 0000          ADD     [BX+SI],AL                             
0CAE:013A 0000          ADD     [BX+SI],AL                             
-g=100 137                                         ;//运行,并设置断点为137 [ret]命令处                    
                                                                       
AX=3570  BX=1C80  CX=0005  DX=0000  SP=FFFE  BP=0000  SI=0000  DI=0000 
DS=0CAE  ES=0CAE  SS=0CAE  CS=0CAE  IP=0137   NV UP EI PL ZR NA PE NC  
0CAE:0137 C3            RET 
------------ 
AX里就是结果了。 
AX = 3570 (十六进制)  转换为十进制是 13680  用windows里的计算器可以进行转换,马上验证一下 
13680 / 30 = 456 
456 * 30 = 13680 
                                          
,我也有一个类似的程序,也是用汇编语言写的,是一个带用户截面的运算器,可以计算加法,减法,乘法,除法,但是只能进行两位数的计算,你如果有空,帮我改进一下,让它的功能更加完善 
;***************************************************************** 
;带用户界面的计算器----可以计算加法,减法,乘法和除法,但是不能计算 
;带括号的四则运算,运行时,先输入两个两位数,再输入运算符号,就能输 
;出计算结果,例如:计算65+79,先输入"65""79",再输入“+?,但是该程序 
;有一个毛病,如果要计算一位数,必须输入两个数字,如果要输入9,必须输 
;入09才行 
;****************************************************************** 
 CURS MACRO A,B 
 MOV AH,2 ;置光标位置 
 MOV BH,0 ;页号为0 
 MOV DH,A ;设置光标的坐标为(A.B) 
 MOV DL,B 
 INT 10H ;BIOS调用 
  
 ENDM 
;------------------------------- 
 DISPMSG MACRO MESSAGE 
 LEA DX,MESSAGE ;传递MESSAGE的偏移地址 
 MOV AH,9 ;显示字符串 
 INT 21H ;DOS调用 
 ENDM 
;---------------------------------- 
 CLEAR MACRO COLOR ;清屏 
 MOV AH,6 ;屏幕初始化 
 MOV AL,0 ;页号 
 MOV CH,0 ;设置左上角的坐标为(0,0) 
 MOV CL,0 
 MOV DL,100 ;设置右上角的坐标为(100,100) 
 MOV DH,100 
 MOV BH,COLOR ;卷入行属性 
 INT 10H ;BIOS调用 
 ENDM 
.MODEL SMALL 
.STACK 
.DATA ;数据段定义 
 MSG0 DB '* * * * * * * * * * * * * * * * * * * *',0DH,0AH ;,0dh,0ah,0dh,0ah 
 DB ' * *',0DH,0AH 
;db	'* *',0dh,0ah 
;db	'* *',0dh,0ah 
 DB ' * --------COUNTER-------- *',0DH,0AH ;,0dh,0ah,0dh,0ah 
 DB ' * *',0DH,0AH 
 DB ' * *',0DH,0AH 
 DB ' * *',0DH,0AH 
 DB ' * DATA1:' 
 DB '_______________ *',0DH,0AH ;,0dh,0ah,0dh,0ah,0dh 
 DB ' * *',0DH,0AH 
 DB ' * *',0DH,0AH 
 DB ' * *',0DH 
 DB ' * DATA2:' 
 DB '_______________ *',0DH,0AH ;,0dh,0ah,0dh,0ah,0dh 
 DB ' * *',0DH,0AH 
 DB ' * *',0DH,0AH 
 DB ' * *',0DH 
 DB ' * RESULT:' 
 DB '_______________ *',0DH,0AH,0DH ;,0ah,0dh,0ah,0dh,0ah,0dh,0ah,0dh,0ah,0dh 
 DB ' * *',0DH,0AH 
 DB ' * *',0DH,0AH 
 DB ' * *',0DH,0AH 
 DB ' * *',0DH,0AH 
 DB ' * *',0DH,0AH 
 DB ' * * * * * * * * * * * * * * * * * * * *','$' 
 MSG1 DB 'choose +,-,*,/','$' 
 MSG2 DB 'you choose wrong','$',0AH,0DH 
 MSG3 DB 'Press ESC to Exit!',0DH,0AH,'$' 
 MSG4 DB 'Press any key to continue!',0DH,0AH,'$' 
 MSG5 DB '-','$' 
 MSG6 DB '.','$' 
 MSG7 DB 'error input!','$' 
 MSG8 DB 'data2 is wrong!','$' 
 DATA1 DW ? 
 DATA2 DW ? 
.CODE ;代码段从这里开始 
;-------------------------------------------- 
 DEC_DIV PROC NEAR 
 CWD ;将字转换为双字,AX内容符号扩展到DX 
 DIV CX 
 PUSH DX 
 MOV DL,AL 
 ADD DL,30H ;将不是数字的字符转换为数字 
 MOV AH,2 ;显示输出 
 INT 21H ;DOS调用 
 POP DX 
 MOV AX,DX 
 RET 
  
 DEC_DIV ENDP 
;------------------------------------------ 
 CHANGE PROC NEAR ;该子程序的功能:将AX中存储的十六进制数转换为十进制数 
 CMP AX,1000 
 JAE C1 ;AX≥1000则转移 
 CMP AX,100 
 JAE C2 ;AX≥100则转移 
 CMP AX,10 
 JAE C3 ;AX≥10则转移 
 JMP C4 ;AX<10 
 C1: MOV CX,1000D 
 CALL DEC_DIV 
 C2: MOV CX,100D 
 CALL DEC_DIV 
 C3: MOV CX,10D 
 CALL DEC_DIV 
 C4: MOV CX,1D 
 CALL DEC_DIV 
 RET 
 CHANGE ENDP 
;------------------------------- 
 BEGIN PROC NEAR 
  
 BACK: CLEAR 1EH 
 CURS 2,20 ;设置光标为(2.20) 
 DISPMSG MSG0 ;显示用户界面
CURS 8,41 ;设置光标为(8,41) ,第一行 
 MOV BX,0 
 MOV CX,2 
 NEWCHAR1: 
 MOV AH,1 ;键盘输入并回显 
 INT 21H ;DOS调用 
 CMP AL,30H ;检查输入的字符是不是数字 
 JAE J1 ;如果不是,则转移至J1 
 JMP D2 ;是,转移到D2执行 
 J1: CMP	AL,39H ; 与9的ASCII侣氡 
 JBE J2 ;如果输入的字符是0-9,则转移至J2 
 JMP D2 ;如果不是数字,则转移至D2 
 J2: SUB AL,30H 
 CBW ;AL的内容符号扩展到AH 
 XCHG AX,BX 
 MOV DI,10 
 MUL DI 
 XCHG AX,BX 
 ADD BX,AX 
 LOOP NEWCHAR1 
 MOV DATA1,BX 
 CURS 11,41 ;设置光标位为(11,40),第二行 
 MOV BX,0 
 MOV CX,2 
 NEWCHAR2: 
 MOV AH,1 ;键盘输入并回显 
 INT 21H ;DOS调用 
 CMP AL,30H ;与0的ASCII码比较 
 JAE J3 ;如果输入数字大于等于0则跳转至J3 
 JMP D2 
 J3: CMP	AL,39H ;与9比较 
 JBE J4 ;如果小于或等于9则跳转 
 JMP D2 ;如果输入不是数字则跳转 
 J4: SUB AL,30H ;如果输入不是0-9,则转化成相应的字符 
 CBW ;将AL符号扩展到AH 
 XCHG AX,BX 
 MOV DI,10 
 MUL DI 
 XCHG AX,BX 
 ADD BX,AX 
 LOOP NEWCHAR2 
 MOV DATA2,BX 
 MOV AX,DATA1 
 MOV BX,DATA2 
 PUSH AX 
 PUSH BX 
 CURS 15,33 ;设置光标的位置为(15.33),第三行 
 DISPMSG MSG1 ;显示提示信息 
 MOV AH,1 ;接受键盘输入并回显 
 INT 21H ;DOS调用 
 CMP AL,'+' 
 JE ADDI ;如果运算符为+,则计算两数之和 
 CMP AL,'-' 
 JE SUBT ;如果运算符为-,则计算两数之差 
 CMP AL,'*' 
 JE MULT ;如果运算符为*,则计算两数之积 
 CMP AL,'/' 
 JE DIVI ;如果运算符为/,则计算两数之商 
 CURS 16,25 ;设置光标为(16,25) 
 DISPMSG MSG2 ;在屏幕上输出提示信息 
 JMP D1 
;---------------------------------------- 
;ADD THE TWO DATAS  
 ADDI: POP BX 
 POP AX 
 ADD AX,BX ;计算两数字之和 
 PUSH AX 
 CURS 14,41 ;设置光标位置为(14,41) 
 POP AX 
 CALL CHANGE ;将结果转换为十进制数 
 JMP D1 
;--------------------------------------- 
;SUBTRACT THE TWO DATAS 
 SUBT: POP BX 
 POP AX 
 CMP AX,BX ;比较两数大小 
 JAE D0 ;如果AX=BX则跳转 
 XCHG AX,BX 
 PUSH AX 
 PUSH BX 
 CURS 14,40 ;设置光标位置为(14,40) 
 DISPMSG MSG5 ;在屏幕上显示负号 
 POP BX 
 POP AX 
 D0: SUB AX,BX ;计算两数之差 
 PUSH AX 
 CURS 14,41 ;设置光标位置为(14,41) 
 POP AX 
 CALL CHANGE ;将结果转换为十进制数 
 JMP D1 
;--------------------------------------- 
;MULTIPLY THE TWO DATAS  
 MULT: POP BX 
 POP AX 
 MUL BX ;计算两数之积 
 PUSH AX 
 CURS 14,41 ;设置光标位置为(14,41) 
 POP AX 
 CALL CHANGE ;将结果转换为十进制数 
 JMP D1 
;--------------------------------------- 
;DIVIDE THE TWO DATAS 
 DIVI: POP BX 
 POP AX 
 CMP BX,0 ;判断除数是否为0 
 JE ERROR ;如果是0则跳转 
 CWD 
 DIV BX ;计算两数之商 
 PUSH DX 
 PUSH AX 
 CURS 14,41 ;设置光标位置为(14,41) 
 POP AX 
 CALL CHANGE ;将十六进制数转换为十进制数 
 POP DX 
 CMP DX,0 
 JNE LOP ;如果DX不等于0则跳转 
 JMP D1 
 LOP: MOV CX,6 ;设置精确度为小数点后6位 
 PUSH DX 
 DISPMSG MSG6 ;输出小数点 
 POP DX 
 CON: PUSH BX 
 MOV AX,DX 
 MOV BX,10 
 MUL BX 
 POP BX 
 CWD ;将AX的内容符号扩展到双字 
 DIV BX ;计算小数点后每一位的数字 
 PUSH DX 
 PUSH CX 
 CALL CHANGE ;将十六进制数转化为十进制数 
 POP CX 
 POP DX 
 CMP DX,0 ;判断是否已经计算到小数点后第六位 
 JE D1 ;如果是,则跳转 
 LOOP CON ;如果不是,就继续计算 
 ERROR: CURS 15,33 ;设置光标位置为(15,33) 
 DISPMSG MSG8 ;提示出错 
 D1: RET 
 D2: PUSH AX 
 PUSH BX 
 CURS 15,33 ;设置光标位置为(15,33) 
 DISPMSG MSG7 ;提示输入出错 
 POP BX 
 POP AX 
 RET 
 BEGIN ENDP 
;---------------------------------------- 
 MAIN PROC NEAR 
  
 MOV AX,@DATA 
 MOV DS,AX 
 MOV ES,AX 
 PUSH DS 
 XOR AX,AX 
 PUSH AX 
 MOV DATA2,0 ;将缓冲区清空 
 MOV DATA1,0 
 AGAIN: 
 CALL BEGIN 
 CURS 16,23 ;设置光标位置为(16.23) 
 DISPMSG MSG3 ;在屏幕上输出提示信息,提示退出的方法 
 CURS 17,23 ;设置光标位置为(17.23) 
 DISPMSG MSG4 ;在屏幕上输出提示信息,提示继续的方法 
 MOV AH,7 ;键盘输入,无回显 
 INT 21H ;DOS调用 
 CMP AL,27 ;判断输入的是否为ESC 
 JNE AGAIN ;如果不是就继续执行以上运算 
 EXIT: MOV AX,4C00H ;如果是就退出系统 
 INT 21H ;DOS调用 
 MAIN ENDP 
 END MAIN
							 
							 
							 
							  
							  
							  楼主 2016-02-04 17:55 回复
						 
						 
           
          
          
         
   
         
      
 
   
             
                  
                  
 
 
 
     
	 
  
	Copyright © 2010~2015 直线网 版权所有,All Rights Reserved.沪ICP备10039589号
	
	意见反馈 | 
	关于直线 | 
	版权声明 | 
	会员须知