【问题标题】:ASSEMBLY - how to do sum between two numbers(interval)组装 - 如何在两个数字之间求和(间隔)
【发布时间】:2015-04-23 09:38:02
【问题描述】:

大家好,可以帮忙吗?我不知道如何在两个数字之间求和 例如:

第一个数字>1

第二个数字>5

总和将 > 1+2+3+4+5 = 15

我只做了两个数字的总和。我不知道如何做这个数字序列,我的代码如下。谢谢

MAIN:
    MOV AX, SEG DATA
    MOV DS,AX

    mov ah, 9h                  ; msg for first number
    lea dx, msg
    int 21H

    mov ah, 1h                  ; read char
    int 21H

    sub al, '0'                 ; strip ASCII
    mov x, al                   ; storing first number

    mov ah, 9h                  ; msg for second number
    lea dx, msg2
    int 21H

    mov ah, 1h                  ; read char
    int 21H

    sub al, '0'
    mov y, al                   ; storing second number

    mov ah, 9h                  ; msg for sum
    lea dx, msg3
    int 21H

    mov dl, x
    add dl, y
    add dl, '0'                 ; x + y

    mov ah, 2h                  ; printing
    int 21H


    MOV AX,4C00H    ;end
    INT 21H

CODE ENDS
    END MAIN

【问题讨论】:

  • 您不仅没有添加您尝试过的内容(这几乎算不上),而且您当前的代码也存在缺陷,它只能处理不超过 9 的总和。

标签: assembly x86


【解决方案1】:

这是伪代码(由你翻译成汇编):

count = firstNumber
endCount = secondNumber + 1
total = 0
while count != endCount
    total = total + count
    count = count + 1

【讨论】:

    【解决方案2】:

    这里是 EMU8086 的解决方案:

    .stack 100h
    
    .data
    
    msj1  db 'Enter first number: $'
    
    msj2  db 'Enter second number: $'
    
    num1  dw ?  ;FIRST  NUMBER OF INTERVAL.
    
    num2  dw ?  ;SECOND NUMBER OF INTERVAL.     
    
    str   db 6         ;MAX NUMBER OF CHARACTERS ALLOWED (4).
          db ?         ;NUMBER OF CHARACTERS ENTERED BY USER.
          db 6 dup (?) ;CHARACTERS ENTERED BY USER. 
    
    crlf  db 13,10,'$'  ;LINE BREAK.
    
    plus  db '+$'  ;PLUS SIGN TO DISPLAY. 
    
    back  db 8,'$' ;CURSOR WILL MOVE ONE PLACE BACK (TO THE LEFT). 
    
    ekual db '=$'  ;EQUAL SIGN TO DISPLAY. 
    
    suma  dw 0  ;SUMATORY OF ALL NUMBERS BETWEEN NUM1 AND NUM2.
    
    .code          
    
    ;INITIALIZE DATA SEGMENT.
      mov  ax, @data
      mov  ds, ax
    
    ;DISPLAY MESSAGE FOR FIRST NUMBER.
      mov  ah, 9
      mov  dx, offset msj1
      int  21h
    
    ;CAPTURE NUMBER AS STRING.
      mov  ah, 0Ah
      mov  dx, offset str
      int  21h
    
    ;CONVERT CAPTURED NUMBER FROM STRING TO NUMERIC.
      mov  si, offset str ;PARAMETER FOR STRING2NUMBER.
      call string2number
      mov  num1, bx      ;RETURNED VALUE.
    
    ;DISPLAY TWO LINE BREAKS.
      mov  ah, 9
      mov  dx, offset crlf
      int  21h
    
      mov  ah, 9
      mov  dx, offset crlf
      int  21h
    
    ;DISPLAY MESSAGE FOR SECOND NUMBER.
      mov  ah, 9
      mov  dx, offset msj2
      int  21h
    
    ;CAPTURE NUMBER AS STRING.
      mov  ah, 0Ah
      mov  dx, offset str
      int  21h
    
    ;CONVERT CAPTURED NUMBER FROM STRING TO NUMERIC.
      mov  si, offset str ;PARAMETER FOR STRING2NUMBER.
      call string2number
      mov  num2, bx      ;RETURNED VALUE.
    
    ;DISPLAY TWO LINE BREAKS.
      mov  ah, 9
      mov  dx, offset crlf
      int  21h
    
      mov  ah, 9
      mov  dx, offset crlf
      int  21h
    
    ;ASURE FIRST NUMBER IS LESS THAN THE SECOND.
      mov  ax, num1
      cmp  ax, num2
      jbe  fine       ;IF AX < NUM2 JUMP FINE.
      xchg ax, num2   ;EXCHANGE : NUM2=AX, AX=NUM2.
      mov  num1, ax   ;NUM1=NUM2.
    fine:
    
    ;DISPLAY THE INTERVAL.
      call display_interval  
    
    ;WAIT UNTIL USER PRESS ANY KEY.
      mov  ah,7
      int  21h
    
    ;FINISH PROGRAM.
      mov  ax, 4c00h
      int  21h           
    
    ;------------------------------------------
    ;DISPLAY ALL NUMBERS BETWEEN NUM1 AND NUM2
    ;SEPARATED BY '+' AND DISPLAYS THE SUM
    
    proc display_interval
    
    interval:    
    ;ADD CURRENT NUMBER TO SUMA.
      mov  ax, num1       ;AX = CURRENT NUMBER.
      add  suma, ax
    ;CONVERT CURRENT NUMBER TO STRING TO DISPLAY IT.
      call dollars        ;FILL "STR" WITH '$'. NEEDED TO DISPLAY.
      call number2string  ;PARAMETER = AX. RETURNS IN VARIABLE "STR".
    ;DISPLAY NUMBER CONVERTED TO STRING.
      mov  ah, 9
      mov  dx, offset str
      int  21h
    ;DISPLAY PLUS SIGN.
      mov  ah, 9
      mov  dx, offset plus
      int  21h
    ;NEXT NUMBER TO DISPLAY.
      inc  num1
      mov  ax, num1
      cmp  ax, num2
      jbe  interval   ;IF AX <= NUM2 THEN REPEAT.
    
    ;DISPLAY THE SUMA.
    
    ;DISPLAY BACKSPACE (TO DELETE LAST PLUS SIGN).
      mov  ah, 9
      mov  dx, offset back
      int  21h
    
    ;DISPLAY EQUAL SIGN.
      mov  ah, 9
      mov  dx, offset ekual
      int  21h
    
    ;CONVERT SUMA TO STRING TO DISPLAY IT.
      call dollars        ;FILL "STR" WITH '$'. NEEDED TO DISPLAY.
      mov  ax, suma
      call number2string  ;PARAMETER = AX. RETURNS IN VARIABLE "STR".
    
    ;DISPLAY NUMBER CONVERTED TO STRING.
      mov  ah, 9
      mov  dx, offset str
      int  21h
    
      ret
    endp  
    
    ;------------------------------------------
    ;CONVERT STRING TO NUMBER IN BX.
    ;SI MUST ENTER POINTING TO THE STRING.
    
    proc string2number
    ;MAKE SI TO POINT TO THE LEAST SIGNIFICANT DIGIT.
      inc  si ;POINTS TO THE NUMBER OF CHARACTERS ENTERED.
      mov  cl, [ si ] ;NUMBER OF CHARACTERS ENTERED.                                         
      mov  ch, 0 ;CLEAR CH, NOW CX==CL.
      add  si, cx ;NOW SI POINTS TO LEAST SIGNIFICANT DIGIT.
    ;CONVERT STRING.
      mov  bx, 0
      mov  bp, 1 ;MULTIPLE OF 10 TO MULTIPLY EVERY DIGIT.
    repeat:         
    ;CONVERT CHARACTER.                    
      mov  al, [ si ] ;CHARACTER TO PROCESS.
      sub  al, 48 ;CONVERT ASCII CHARACTER TO DIGIT.
      mov  ah, 0 ;CLEAR AH, NOW AX==AL.
      mul  bp ;AX*BP = DX:AX.
      add  bx,ax ;ADD RESULT TO BX. 
    ;INCREASE MULTIPLE OF 10 (1, 10, 100...).
      mov  ax, bp
      mov  bp, 10
      mul  bp ;AX*10 = DX:AX.
      mov  bp, ax ;NEW MULTIPLE OF 10.  
    ;CHECK IF WE HAVE FINISHED.
      dec  si ;NEXT DIGIT TO PROCESS.
      loop repeat ;COUNTER CX-1, IF NOT ZERO, REPEAT.
    
      ret 
    endp    
    
    ;------------------------------------------
    ;FILLS VARIABLE STR WITH '$'.
    ;USED BEFORE CONVERT NUMBERS TO STRING, BECAUSE
    ;THE STRING WILL BE DISPLAYED.
    
    proc dollars                 
      mov  si, offset str
      mov  cx, 6
    six_dollars:      
      mov  bl, '$'
      mov  [ si ], bl
      inc  si
      loop six_dollars
    
      ret
    endp  
    
    ;------------------------------------------
    ;NUMBER TO CONVERT MUST ENTER IN AX.
    ;ALGORITHM : EXTRACT DIGITS ONE BY ONE, STORE
    ;THEM IN STACK, THEN EXTRACT THEM IN REVERSE
    ;ORDER TO CONSTRUCT STRING (STR).
    
    proc number2string
      mov  bx, 10 ;DIGITS ARE EXTRACTED DIVIDING BY 10.
      mov  cx, 0 ;COUNTER FOR EXTRACTED DIGITS.
    cycle1:       
      mov  dx, 0 ;NECESSARY TO DIVIDE BY BX.
      div  bx ;DX:AX / 10 = AX:QUOTIENT DX:REMAINDER.
      push dx ;PRESERVE DIGIT EXTRACTED FOR LATER.
      inc  cx ;INCREASE COUNTER FOR EVERY DIGIT EXTRACTED.
      cmp  ax, 0  ;IF NUMBER IS
      jne  cycle1 ;NOT ZERO, LOOP. 
    ;NOW RETRIEVE PUSHED DIGITS.
      mov  si, offset str
    cycle2:  
      pop  dx        
      add  dl, 48 ;CONVERT DIGIT TO CHARACTER.
      mov  [ si ], dl
      inc  si
      loop cycle2  
    
      ret
    endp  
    

    接下来是您的代码进行了一些更改,现在它从堆栈中获取两个参数,并在内部将它们放入变量 num1 和 num2 中。我没有处理所有“打印”的参数:

    proc display_interval
    
    ;RETRIEVE PARAMETERS.
        pop   ax    ;RETURN ADDRESS.
        pop   num2  ;NUM2.
        pop   num1  ;NUM1.
        push  ax    ;RETURN ADDRESS BACK (NECESSARY FOR "RET").
    
        print msg4
    interval:    
        ;ADD CURRENT NUMBER TO SUMA.
          mov  ax, x       ;AX = CURRENT NUMBER.
          add  k, ax
        ;CONVERT CURRENT NUMBER TO STRING TO DISPLAY IT.
          call dollars        ;FILL "STR" WITH '$'. NEEDED TO DISPLAY.
          call number2string  ;PARAMETER = AX. RETURNS IN VARIABLE "STR".
        ;DISPLAY NUMBER CONVERTED TO STRING.
          mov  ah, 9
          mov  dx, offset str
          int  21h
        ;DISPLAY PLUS SIGN.
          mov  ah, 9
          mov  dx, offset plus
          int  21h
        ;NEXT NUMBER TO DISPLAY.
          inc  x
          mov  ax, x
          cmp  ax, y
          jbe  interval   ;IF AX <= NUM2 THEN REPEAT.
    
        ;DISPLAY THE SUMA.
    
        ;DISPLAY BACKSPACE (TO DELETE LAST PLUS SIGN).
          print back
    
        ;DISPLAY EQUAL SIGN.
          print equal
    
        ;CONVERT SUMA TO STRING TO DISPLAY IT.
          call dollars        ;FILL "STR" WITH '$'. NEEDED TO DISPLAY.
          mov  ax, k
          call number2string  ;PARAMETER = AX. RETURNS IN VARIABLE "STR".
    
        ;DISPLAY NUMBER CONVERTED TO STRING.
          mov  ah, 9
          mov  dx, offset str
          int  21h
    
          ret
    endp  
    

    程序“display_interval”应该这样调用:

    mov  ax, 1
    push ax      ;FIRST PARAMETER.
    mov  ax, 5
    push ax      ;SECOND PARAMETER.
    call display_interval
    

    【讨论】:

    • 非常感谢!!还有一个问题。如果我想从下面的 n 行中跳转,我该怎么办。它应该通过返回值而不是跳转。示例> 调用 proc(row) CALL proc 和例如来自过程的 ret 跳转到 CALL proc 下方 6 行
    • 我不确定你的问题。无论如何,如果您在不执行 RET 的情况下跳转,堆栈可能会有垃圾,也可能没有,我需要查看代码以了解您的目标(发布代码以便我查看),但是,如果您想往下跳n行,可以做一个正常的跳转,在这个跳转后做RET,这样栈就OK了。问:你为什么不接受我的回答,有什么问题吗,运行不好吗?
    • 不,没关系 :) 我只是对跳跃感到好奇。我稍后会发布代码以便您理解,但现在我有更重要的问题。我正在尝试使用参数 (num1,num2) 执行您的程序(display_interval),但进展不顺利,如何在程序中声明参数? x:DWORD, y:DWORD 像这样?
    • #1 :将参数压入堆栈并将它们弹出到过程中(记住弹出返回地址并将其压回)。 #2 将参数放在您目前不使用的寄存器上。 #3 将参数放入数据段中声明的变量中。
    • 要使用高级语言参数样式,您需要使用内联汇编程序。接下来是 VS2010 C++ 的示例:stackoverflow.com/questions/29830481/…。它是一种传统的方法 void number2string ( int value ),但它的内部是“内联汇编器”。
    【解决方案3】:

    您可以使用条件跳转来执行此操作。 下面是一个简单的代码 sn-p 其中ebx 包含要添加的当前数字,ecx 包含循环将运行的次数(即second_number - first_number +1)。 sum 将存储在 eax 中。

    mov eax,0               ; initialise sum with 0
    mov ebx,dword[first_number]    ;initialise ebx with first_number
    mov ecx,dword[second_number]  
    sub ecx,dword[first_number]
    inc ecx                 ; ecx content will be end_number - start_number + 1, now
    calculation:            ; after calculation sum can be accessed from eax
            add eax,ebx     ; sum = sum + ebx content
            inc ebx         ; ebx = ebx + 1
            dec ecx         ; ecx = ecx - 1
            cmp ecx,0h      ; ecx == 0 ?
            jne calculation ; if not then once again go through calculation.
    

    【讨论】:

      【解决方案4】:
      proc display_interval
      
          push BP                 
          mov BP, SP
          mov AX, [BP+4]
          mov SP, BP
          pop BP
      
          print msg4
      interval:    
          mov  ax, num1       ;AX = CURRENT NUMBER.
          add  suma, ax
          ;CONVERT CURRENT NUMBER TO STRING.
          call dollars        ;FILL "STR" WITH '$'.
          call number2string  ;PARAMETER = AX.
      
          mov  ah, 9
          mov  dx, offset str
          int  21h
      
          mov  ah, 9
          mov  dx, offset plus
          int  21h
      
          inc  num1
          mov  ax, num1
          cmp  ax, num2
          jbe  interval   ;IF AX <= NUM2
      
      
          ;BACKSPACE (DELETE LAST +).
          print back
          print equal
      
          call dollars        ;FILL "STR" WITH '$'.
          mov  ax, suma
          call number2string  ;PARAMETER = AX.
      
          mov  ah, 9
          mov  dx, offset str
          int  21h
      
          ;-------------------------------------------
          ;IF SUMA IS EVEN RET WILL JUMP FEW ROWS BELOW(d2)
          mov dx,0                ;dividing
          mov bl,suma
          mov ax,bx
          mov cl,2
          div cl                  ;the remainder from division stores in AH
          mov dl,ah
          add dl,48               ;48 ASCII is 0, for compare
          cmp dl,48               ;0?
          je  d2                  
                                  ;dividing end
          pop ax
          mov sp,bp
          pop bp
          ret                     ;normal RET
      
      d2: pop ax
          mov dx,583              ;number whitch it jumps from RET
          mov [bp+2],dx
          mov sp,bp
          pop bp
          ret                     ; jumping RET, if suma is even
      
      endp  
      

      【讨论】:

      • 我相信你的堆栈中有不一致的地方。在调用之前推送参数。所以,在程序开始时弹出参数(这是我的风格)。更安全。
      • 是的工作,还有一件事是可以用负数求和吗?
      • 负数没有问题,问题是从数字转换为字符串的过程,因为它是为正数制作的,但您可以轻松修复它:在调用 number2string 之前,如果数字是负数,将其乘以 -1 使其为正数,调用 number2string,并在结果字符串的开头添加字符“-”。
      • 如果第一个数字更大,你能告诉我怎么做吗?我尝试了 cmp num1,num2 -> 如果 num1 和 num2 的变化更大,则跳转,但它无法以某种方式工作,你可以编辑:)
      • 完成。检查我原始答案中的评论“确保第一个数字小于第二个”。我没有运行代码。你运行它,如果你有任何问题,请告诉我。
      猜你喜欢
      • 2011-03-07
      • 2022-08-08
      • 2021-09-28
      • 1970-01-01
      • 2013-10-08
      • 1970-01-01
      • 1970-01-01
      • 2022-06-01
      相关资源
      最近更新 更多