使用 TASM 进行二进制除法。运行时很难获得准确的商

问题描述 投票:0回答:1

这是代码,您认为它为什么不断产生错误的商有什么问题。

divide proc
    ; Set cursor position for PROMPT_1
    mov ah, 02h
    mov bh, 00h
    mov dh, 0Bh ; row
    mov dl, 0Ah ; column
    int 10h
    
    ; Display the prompt for the first number
    mov dx, offset PROMPT_1 ;(THIS IS THE FIRST BINARY INPUT)
    mov ah, 09h
    int 21h

    ; Initialize the dividend to zero
    xor bl, bl

    ; Read the first binary number
    mov cx, 8
    mov ah, 01h

@DIV_LOOP_1:
    int 21h
    cmp al, 0Dh
    jne @DIV_SKIP_1
    jmp @DIV_EXIT_LOOP_1

@DIV_SKIP_1:
    and al, 0Fh
    shl bl, 1
    or bl, al
    loop @DIV_LOOP_1

@DIV_EXIT_LOOP_1:
    
    ; Set cursor position for PROMPT_2 
    mov ah, 02h
    mov bh, 00h
    mov dh, 0Ch ; row
    mov dl, 0Ah ; column
    int 10h
    
    ; Display the prompt for the second number
    mov dx, offset PROMPT_2 ;(THIS IS THE SECOND BINARY INPUT)
    mov ah, 09h
    int 21h

    ; Initialize the divisor to zero
    xor bh, bh

    ; Read the second binary number
    mov cx, 8
    mov ah, 01h

@DIV_LOOP_2:
    int 21h
    cmp al, 0Dh
    jne @DIV_SKIP_2
    jmp @DIV_EXIT_LOOP_2

@DIV_SKIP_2:
    and al, 0Fh
    shl bh, 1
    or bh, al
    loop @DIV_LOOP_2

@DIV_EXIT_LOOP_2:

    ; Perform binary division
    xor ch, ch  ; quotient
    xor dl, dl  ; temporary register for subtraction result
    mov cl, bl  ; move dividend to cl

    ; Ensure divisor is not zero to avoid division by zero
    cmp bh, 0
    je @DIV_DIVISION_ERROR

    mov dl, 8  ; bit position counter

@DIV_DIVISION_SHIFT:
    shl cl, 1  ; shift left the dividend
    rol ch, 1  ; rotate left the quotient to shift in a new bit
    sub cl, bh ; attempt to subtract divisor from dividend
    jc @DIV_SUBTRACTION_FAILED
    or ch, 1   ; if no carry, set LSB of quotient
    jmp @DIV_SUBTRACTION_DONE

@DIV_SUBTRACTION_FAILED:
    add cl, bh ; restore dividend if subtraction failed

@DIV_SUBTRACTION_DONE:
    dec dl
    jnz @DIV_DIVISION_SHIFT

    ; Set cursor position for PROMPT_3
    mov ah, 02h
    mov bh, 00h
    mov dh, 0Dh ; row
    mov dl, 0Ah ; column
    int 10h
    
    ; Display the result label
    mov dx, offset DIV_PROMPT_3
    mov ah, 09h
    int 21h

    ; Display the result (quotient)
    mov bl, ch
    call DISPLAY_BINARY

    ; Pause for user input
    mov ah, 01h
    int 21h
    
    ret

@DIV_DIVISION_ERROR:
    ; Handle division by zero error
    mov ah, 09h
    mov dx, offset DIVISION_ERROR_MSG
    int 21h
    jmp @DIV_END_PROGRAM

@DIV_END_PROGRAM:
    ; Pause for user input
    mov ah, 01h
    int 21h
    ret

DISPLAY_BINARY:
    ; Convert and display the binary number in BL
    mov cx, 8
    mov ah, 02h

@DISPLAY_LOOP:
    shl bl, 1
    jc @ONE_BIT
    mov dl, 30h
    jmp @DISPLAY_BIT

@ONE_BIT:
    mov dl, 31h

@DISPLAY_BIT:
    int 21h
    loop @DISPLAY_LOOP
    ret

; Pause for user input
mov ah, 01h
int 21h

ret

我尝试了不同的方法来解决这个问题,但它总是产生错误的商。你能检查一下我的代码有什么问题吗?

显示是这样的

 PROMPT_1  DB 'INPUT FIRST NUMBER [000-111]: $'
 PROMPT_2  DB 'INPUT SECOND NUMBER [000-111]: $'
assembly x86-16 tasm
1个回答
0
投票

它不断产生错误的商。你能检查一下我的代码有什么问题吗?

你的输入和输出例程很好,但实际的除法算法在我看来是不可挽救的。

三种解决方案

以下所有代码都将 AL 除以 BL,在 AL 中产生商,在 AH 中产生余数。

使用字节大小
div

您的问题中没有任何地方提到限制不使用

div
指令。所以这里是:

  test bl, bl
  jz   @DIV_DIVISION_ERROR
  mov  ah, 0
  div  bl          ; AX / BL  ->  AL is quotient, AH is remainder

使用重复减法

这是迄今为止最简单的替代解决方案; (不使用

div
指令的解决方案):

  test bl, bl
  jz   @DIV_DIVISION_ERROR
  mov  ah, 0     ; Temporary quotient
.a:
  inc  ah
  sub  al, bl
  jnb  .a
  dec  ah
  add  al, bl
  xchg al, ah    ; -> AL is quotient, AH is remainder

使用试减法

快得多,可能就是您的目标,但仍然没有使用

div
指令:

  xor  dl, dl    ; Quotient under construction
  mov  cl, 1     ; Nominal weight of the divisor BL
  test bl, bl
  jz   @DIV_DIVISION_ERROR
  js   .Subtract ; Divisor already occupies MSB of its byte-sized container
.ShiftUp:
  shl  cl, 1     ; Adjust the weight of the current divisor
  shl  bl, 1     ; Double the current divisor
  jns  .ShiftUp  ; Until at MSB of the byte-sized container
.Subtract:
  cmp  bl, al    ; Could we borrow-less subtract current divisor from dividend ?
  ja   .Skip     ; No, then skip
  add  dl, cl    ; Add current weight to quotient under construction
  sub  al, bl    ; Lower dividend by current divisor (building remainder)
.Skip:
  shr  bl, 1     ; Try next lower divisor
  shr  cl, 1     ; Adjust to lesser weight
  jnz  .Subtract ; Repeat for as long as there is weight
  mov  ah, al    ; -> AH is remainder
  mov  al, dl    ; -> AL is quotient
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.