EMU8086中16位乘法32位结果的正确输出方法咨询
问题:EMU 8086中16位乘法结果的高低字合并输出错误
以下是我在EMU 8086中用于两个16位数字相乘的代码:
mov ax, [integerOp1] mul [integerOp2] mov resultHi, dx mov resultLo, ax ;Integer -> ASCII mov cx, 0 ; Count for digits in result @IterateMulLo: cwd ; Preventing Division Overflow mov bx, 10 div bx ; Dividing by 10 to get the digits of result as remainder mov dh, 00h ; Clearing dh so dx conatins just the digit add dl, 30h ; Converting digit in dl to ASCII push dx ; Pushing the ASCII to stack inc cx ; Increment digit count cmp ax, 0 ; Repeating process until quoteint reaches 0. i.e: no more digits left jg @IterateMulLo mov digitCount, cx mov ax, resultHi @IterateMulHi: cwd ; Preventing Division Overflow mov bx, 10 div bx ; Dividing by 10 to get the digits of result as remainder mov dh, 00h ; Clearing dh so dx conatins just the digit add dl, 30h ; Converting digit in dl to ASCII push dx ; Pushing the ASCII to stack inc cx ; Increment digit count cmp ax, 0 ; Repeating process until quoteint reaches 0. i.e: no more digits left jg @IterateMulHi mov digitCount, cx jmp @Result
乘法指令mul [integerOp2]会将结果存储在DX(高字)和AX(低字)中。以十进制1234*1234为例,DX中的值为0017(十六进制),AX中的值为3C44(十六进制),合并后得到00173C44(十六进制)=1522756(十进制),这是正确结果。但我分别将这两个值入栈再弹出显示时,得到的结果是2315428(即DX的十进制值23加上AX的十进制值15428),结果错误。请问如何合并高低字以输出正确的结果?
解决方案
问题根源
你当前的代码是将低字(AX)和高字(DX)作为两个独立的16位整数分别转换为十进制,再将结果拼接,这相当于把高字的十进制数值直接放在低字的十进制数值前面,而非将DX:AX视为一个完整的32位整数处理,因此得到错误结果。
修正代码(适用于商≤16位的场景)
需要将DX:AX(或存储后的resultHi:resultLo)作为一个完整的32位无符号数来转换为ASCII,以下是修正后的转换部分代码:
; 乘法完成后,先保存32位结果到变量(可选) mov resultHi, dx mov resultLo, ax ; 32位整数转ASCII,结果入栈,CX为数字个数 mov cx, 0 mov bx, 10 ; 除数设为10 ; 加载完整32位结果到DX:AX mov ax, resultLo mov dx, resultHi @IterateWholeResult: div bx ; DX:AX / 10,商存AX,余数存DX add dl, 30h ; 余数转ASCII字符 push dx ; 入栈保存字符 inc cx ; 数字计数+1 mov dx, 0 ; 清零DX,准备处理下一轮的商(AX为商的低16位) cmp ax, 0 ; 判断商是否为0 jg @IterateWholeResult mov digitCount, cx jmp @Result
兼容超大数值的方案(避免除法溢出)
如果需要处理商超过16位的超大数值(如65535*65535的结果),上述直接使用div的方法会触发除法溢出,此时需要模拟32位除法:
; 乘法完成后保存结果 mov resultHi, dx mov resultLo, ax mov cx, 0 mov bx, 10 @IterateBigResult: push ax ; 先处理高16位 mov ax, resultHi xor dx, dx div bx mov resultHi, ax ; 保存高16位的商 mov ax, dx ; 取高16位的余数 shl ax, 16 ; 余数左移16位,和低16位合并 pop ax add ax, resultLo ; 合并余数与原低16位 div bx ; 计算最终余数和低16位的商 push dx ; 余数转ASCII后入栈 add dl, 30h inc cx mov resultLo, ax ; 更新低16位的商 ; 判断整个32位商是否为0 mov ax, resultHi or ax, resultLo jnz @IterateBigResult mov digitCount, cx jmp @Result
验证逻辑
以你的示例1234*1234=1522756为例,修正后的代码会将0017h:3C44h作为整体处理:
- 第一次除以10,余数6(ASCII '6')入栈,商为152275;
- 重复除以10,依次得到余数5、7、2、2、5、1,分别入栈;
- 最终弹出栈的顺序为1、5、2、2、7、5、6,组合后就是正确结果
1522756。
内容的提问来源于stack exchange,提问作者MUHAMMAD AWAIS
相关产品推荐
相关产品推荐

