assembly 汇编语言除法(问题是求余数)

mctunoxg  于 2023-03-02  发布在  其他
关注(0)|答案(1)|浏览(183)
jmp start

  mess1 db 'Enter 1st number: $'
  mess2 db 0a,0d, 'Enter 2nd number: $'
  nextline db 0a,0d, '$'

start:

  mov ax, 03
  int 10h

  mov dx, offset mess1
  call printstring
  call input
  sub al, 30h
  push ax

  mov dx, offset mess2
  call printstring
  call input
  mov bl, al
  mov dx, offset nextline
  call printstring
  sub cl, 30h
  sub bl, 30h
  pop ax

  mov ah, 0
  aad
  div bl

  mov dl, al
  add dl, 30h

  push ax
  call printchar

  mov dl, '.'
  call printchar
  mov ah, 0
  pop ax
  mov dl, ah
  add dl, 30h
  call printchar
  int 20h

input:
  mov ah, 1
  int 21h
  ret

printstring:
  mov ah, 9
  int 21h
  ret

printchar:
  mov ah, 2
  int 21h
  ret

它在余数为0时起作用,但只有当方程有余数时,余数才会显示错误的数字。

rta7y2nd

rta7y2nd1#

余数是分数的分子。例如,"5/3 = 1,余数为2"(因为"5-(1 * 3)= 2"),所以真实结果为"1 + 2/3"(或"商+余数/除数")。请注意,许多分数是循环小数,"1 + 2/3"为数字2.66666666 ...
最简单的显示方法是将其显示为分数(例如打印余数、"/"符号和除数)。
将其打印为小数;您可以重复地将"余数/除数"乘以10并提取整数部分。Eidogg."2 * 10/3 = 6,余数为2",这样您就可以打印"6"并使用新的余数再次进行打印,对于本例来说,新的余数将是相同的,所以你最终会重复打印"6"(直到你因为其他原因停止打印--例如,因为你把它限制在3位数)。你会得到"1 * 10/8 = 1余数为22 * 10/8 = 2,余数为4;4 * 10/8 = 5,余数为0 ",得到数字1、2和5。
另一个问题是,这将向零截断,而人类更喜欢"四舍五入"-例如,对于"5/3",你最终会打印"5.666",而人类会想要"5.667"。为了解决这个问题,如果你在小数点后计算3位数,你会想要在开始时将0.0005添加到原始余数中。并且为了对分数进行该运算,其最终是交叉乘法-例如"余数/除数+1/2000 =(余数 * 2000)/(除数 * 2000)+除数/(除数 * 2000)=(余数 * 2000 + 1)/(除数 * 2000)"。
换句话说如果在将分数转换为三位小数之前执行"余数=余数 * 2000 + 1"和"除数=除数 * 2000",则会得到正确的四舍五入结果。* 注意:在某些情况下,这种舍入可能会改变整数部分-例如,值3.99987654321应该显示为"4.000",但如果您不小心,您会显示为"3.000"。幸运的是,您不必担心这种情况(因为除数总是从1到9的数字)。*
装配中;可能如下所示(NASM语法,未测试):

; ax = number1, bl = number2

    div bl                 ;ah = remainder, al = quotient

    ;Do integer part

    mov dl,al              ;dl = quotient
    call printchar         ;Print the quotient

    ;Prepare for fractional part

    shr ax,8               ;ax = remainder (from 0 to 9)
    mov cx,2000
    mul cx                 ;dx:ax = ax = remainder*2000 (from 0 to 18000)
    push ax
    mov ax,bx              ;ax = divisor (from 1 to 9)
    mul cx                 ;dx:ax = ax = divisor*2000 (from 2000 to 18000)
    mov bx,ax              ;bx = divisor*2000 (from 2000 to 18000)
    pop ax                 ;ax = remainder*2000 (from 0 to 18000)
    inc ax                 ;ax = remainder*2000+1 (from 1 to 18001)
    mov cx,10              ;cx = 10

    mov dl,'.'
    call printchar         ;Print the decimal point

    ;Do the first fractional digit

    mul cx                 ;dx:ax = (remainder*2000+1) * 10 (from 10 to 180010)
    div bx                 ;ax = (remainder*2000+1) / (divisor*2000); dx = next_remainder (from 0 to 18000)
    push dx
    mov dl,al
    call printchar         ;Print the first factional digit
    pop ax                 ;ax = next_remainder (from 0 to 18000)

    ;Do the second fractional digit

    mul cx                 ;dx:ax = next_remainder * 10 (from 10 to 180000)
    div bx                 ;ax = (next_remainder*10) / (divisor*2000); dx = next remainder
    push dx
    mov dl,al
    call printchar         ;Print the second factional digit
    pop ax                 ;ax = next_remainder (from 0 to 18000)

    ;Do the last fractional digit

    mul cx                 ;dx:ax = next_remainder * 10 (from 10 to 180000)
    div bx                 ;ax = (next_remainder*10) / (divisor*2000); dx = next remainder
    mov dl,al
    call printchar         ;Print the third factional digit

请注意,跟踪变量范围非常重要(例如,正如我在上面的注解中所做的那样),以确保没有溢出错误。例如,从10到180000的整数值将不适合16位(并且不适合AX这样的16位寄存器),我们只是幸运地使用了指令集,在这些情况下可以很容易地使用一对寄存器("dx:ax"或"DX中的最高16位和AX中的最低16位")。

相关问题