【问题标题】:How to display a 64 bit number in decimal in assembly 8086如何在汇编 8086 中以十进制显示 64 位数字
【发布时间】:2014-07-15 17:34:05
【问题描述】:

我正在处理一项作业,但遇到了除法溢出问题。
它给出了一个错误,因为我将一个 64 位数字 DX AX 除以一个 32 位数字。答案不适合AX,因此会出错。

有没有办法克服这种溢出?我想把这个数字转换成十进制,所以我想把它除以 10。

【问题讨论】:

  • 您可以实现除法算法或使用 10 的幂的重复减法。
  • axdx 是 16 位寄存器。其中两个只能组成一个32位的伪寄存器,不能组成一个64位的。你需要eax:edx,它只能从 80386 开始使用。
  • EOF 的回复是 cmets 需要 downvoting 功能的原因。这不是很有帮助,似乎不理解这个问题。显然,您可以对可用寄存器而言太大的数字进行算术运算 - 如下面的正确答案所示。

标签: assembly overflow emulation x86-16 divide


【解决方案1】:

以 edx = 0 开头,eax = 被除数的高位。除以 10,eax 将是下一个循环的最高除数,所以保存它。 edx 将有余数,用于下一次除法: eax = 被除数的低位。除以 10,eax 将是下一个循环的较低股息,所以保存它。 edx 将是 64 位被除数除以 10 的余数,这将是该数字的最低有效十进制数字。重复循环,以相反的顺序获取数字。

针对下面的评论,假设 64 位数字在 EDI:ESI (high:low) 中:

        mov     ecx,10
loop0:  xor     edx,edx         ;divide high order by 10
        mov     eax,edi
        div     ecx
        mov     edi,eax
        mov     eax,esi         ;divide low  order by 10
        div     ecx
        mov     esi,eax
;                               ;at this point edx contains one decimal digit
;       ...                     ;store the digit and continue with the loop

【讨论】:

  • 我不能以 dx = 0 开头。我的号码是 64 位数字 DX-AX。我想在 10 点之前完成,请回复:/
  • 我更新了答案以显示代码。您可以编写其余代码以将数字以相反的顺序转换为 ascii 字符串。
【解决方案2】:

从 rcgldr 获得灵感

这是在 8086 中的实现方式,因为 8086 中的所有寄存器都是 16 位的

                                ;here we have a 64bit number in si:di:cx:bx
loop0:  xor dx,dx
        mov ax,si               ;divide highes order by 10
        div diver
        mov si,ax
        mov ax,di               ;divide high order by 10
        div diver
        mov di,ax
        mov ax,cx               ;divide low oreder by 10
        div diver
        mov cx,ax
        mov ax,bx               ;divide lowest order by 10
        div diver
        mov bx,ax
                                ;right now we have the wanted number in dx
        mov temp,si             ;keep value of si for later
        mov si,[bp+4]           ;make si point to wanted string
        add si,18               ;move to end of string
        sub si,counter          ;move back the amount of times used
        add dx,'0'
        mov byte ptr [si],dl
        inc counter
        mov si,temp             ;put back saved value in si and go again
        cmp si,0
        jne loop0
        cmp di,0
        jne loop0
        cmp cx,0
        jne loop0
        cmp dx,0
        jne loop0
        mov counter,0           ;reset counter

我试图解决一个类似的问题 2 天!!直到我读到 rcgldr 的回答。谢谢!唯一的区别是我需要在 386 环境中将 64 位数字除以 10 而不是 8086 但它都是一样的 并且由于您的问题对我有帮助,因此我在 8086 中为您编写了此代码。

希望对某人有所帮助...

【讨论】:

  • 我认为描述从 MSB 到 LSB 的 64 位值可能会更好:si:di:cx:bx 而不是 bx:cx:di:si
  • 很有趣。我很想知道为什么?会有什么不同?
  • 我并不是建议对代码进行更改(只是注释),但大多数情况下,当您在多个寄存器中有一个多部分值时,您会从最重要到最不重要列出它们。它与英特尔的做法保持一致。例如,在 x86 上,dx:axedx:eaxrdx:rax 使用类似的符号,其中最重要的部分列在最前面,最不重要的部分出现在最后,每个都用冒号分隔。当我在您的代码中看到注释时,我自动认为是 MSB 到 LSB,直到我注意到代码朝另一个方向发展。
  • 是的,但这些寄存器只保存 64 位数字。如果我愿意,我可以使用veriables,它仍然可以正常工作,我想。我只是一个学生(即将在 90 分钟内参加这个课程的期末考试)祝我好运;)
  • 循环将退出太早,因为它没有检查整个 64 位数字是否变为零!
【解决方案3】:

上显示DI:SI:CX:BX 中的64 位数字

步骤 1. 计算数字

这需要使用从 64 位数的最高有效字开始的一系列除法。每个除法的余数在下一次除法中重复使用。

  mov  bp, 10  ;Constant divider 10
  push bp      ;Will signal the end of the PUSHed remainders
Next:
  xor  dx, dx
  xchg ax, di  ;Most Significant Word is in DI
  div  bp      ;Divide Word3
  xchg di, ax
  xchg ax, si
  div  bp      ;Divide Word2
  xchg si, ax
  xchg ax, cx
  div  bp      ;Divide Word1
  xchg cx, ax
  xchg ax, bx  ;Least Significant Word is in BX
  div  bp      ;Divide Word0
  mov  bx, ax

  push dx      ;Every remainder is [0,9]

  or   ax, cx  ;OR all quotients together
  or   ax, si
  or   ax, di
  jnz  Next    ;Repeat while 64-bit number not zero

请注意xchg 指令用于减少代码大小!

步骤 2. 显示数字

为了显示字符,我假设这是在 DOS 上运行的。
应该很容易将其适应另一个操作系统...

  pop  dx      ;This is digit for sure
More:
  add  dl, '0' ;Convert from remainder [0,9] to character ["0","9"]
  mov  ah, 02h
  int  21h     ;DisplayCharacter
  pop  dx
  cmp  dx, bp  ;Repeat until it was the 'signal (bp=10)' that was POPed
  jb   More

【讨论】:

    猜你喜欢
    • 2017-07-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-02
    • 2014-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多