【问题标题】:How to calculate average? (masm x86 8086)如何计算平均值? (masm x86 8086)
【发布时间】:2016-05-16 05:01:53
【问题描述】:

我试图在 MASM x86(我使用 8086)上找到两个用户输入数字的平均值。我似乎无法计算平均值!我可以让这两个数字相乘,但我不知道如何将它们相加,然后将它们除以数字的总数(在我的情况下它只有 2)。这是我到目前为止所拥有的(是的,我意识到我在相乘,但这只是表明我确实尝试了一些东西,我只是不能让他们加和除总和):

.model small
org 100h
.data

num1 db ?
num2 db ?
result db ? 
usermsg db "Enter EVEN numbers only.$"
msg1 db 13, 10, "Enter first number: $"
msg2 db 13, 10, "Enter second number: $"
msg3 db 13, 10, "The average is: $"

.code

main proc
mov ax, @data
mov ds, ax

lea dx, usermsg
mov ah, 09h
int 21h

lea dx, msg1
mov ah, 09h
int 21h

mov ah, 01h
int 21h

sub al, '0'
mov num1, al 
mov dl, al

lea dx, msg2
mov ah, 09h
int 21h

mov ah, 01h
int 21h
sub al, '0'
mov num2, al

mul num1


;add al, num1

mov result, al


idiv result, 2 ;new code
aam

add ah, '0'
add al, '0'
mov bx, ax

lea dx, msg3
mov ah, 09h
int 21h

mov ah, 02h
mov dl, bh
int 21h
mov dl, bl
int 21h

mov ax, 4c00h
int 21h

【问题讨论】:

    标签: assembly average masm emu8086


    【解决方案1】:

    只需将您的号码添加到寄存器中并除以即可。如果它们足够小,总和不会溢出,那就很容易了。

    如果您提前知道您只是平均 2 个数字(或 2 的任何幂),请使用移位除法。

    ...  your original code that gets two digits from the user
    sub   al, '0'
    ; first number in [num1] in memory, second number in al
    ; We know they're both single-digit numbers, so their sum will fit in 8bits
    
    
    add   al, [num1]    ; or whever you put num1: a register like cl would be a good choice, instead of memory
    shr   al, 1         ;  al = al/2  (unsigned)
    
    ;; al holds the average.  Do whatever else you want.
    
    mov   [result], al  
    add   al, '0'       ; convert back to ASCII
    

    您可以在不减去和重新添加'0' 的情况下平均两个 ASCII 数字,以保存指令。如果asc='0'(即0x30),那么

      (a+asc + b+asc) / 2
    = (a+b)/2 + (asc+asc)/2
    = (a+b)/2 + asc        i.e. the average as an ASCII digit
    

    因此:

    add  al, [asciidigit1]
    shr  al, 1
    

    例如'5' + '8' = 0x6d. 0x6d>>1 = 0x36 = '6'.


    你的idiv有问题:

    没有form of idiv 接受立即操作数。被除数是隐式的,除数是一个显式操作数。商进入 AL,余数进入 AH。 (这与AAM 相反,它接受立即操作数,但只除 AL,而不是 AX)。

    参见 this answer to another question,我在其中演示了使用 divaam 将整数转换为两个 ASCII 数字(并使用 DOS 系统调用打印它们,因为那是该问题的 OP 想要的)。

    另请参阅 标签 wiki 中的其他链接。

    【讨论】:

    • 非常感谢您抽出宝贵时间回答我的问题。我现在确实有另一个问题,所以我基本上必须打印“结果”的内容才能打印出平均值?
    • 另外,用户只会输入两个偶数整数,所以除以二来取平均值就可以了。
    • @howardhoward:是的,当你完成后,结果是al 中的一个ASCII 数字。如果您正在编写一个函数(main() 以外的函数),那么通常的情况就是 ret,返回值在 eaxaxal 中(取决于返回类型) .您可以让函数将其存储到静态内存中的[result] 中,但没有必要这样做。如果它是一个函数,那么调用者可以打印它想要的任何操作的返回值。由于此代码只是您的主程序的一部分,因此请务必将 al 打印为 ASCII 字符。
    【解决方案2】:

    对asm了解不多,但是你确定可以这样用idiv吗?

    这个:http://www.electronics.dit.ie/staff/tscarff/8086_instruction_set/8086_instruction_set.html#IDIV 说您将“结果”加载到 AX 中,然后进入 idiv 2,结果将进入 AL。所以我想你会尝试

    ;add al, num1
    
    movzx ax, al
    mov   dl, 2
    idiv  dl
    

    AL 将包含除法的结果(商),AH 将包含余数。


    或者,因为您要除以 2,所以您应该只右移 1。目标可以是寄存器或内存

    shr result,1
    

    将“结果”右移 1 位并将答案存储在“结果”中

    【讨论】:

    • 你是对的,没有任何形式的 idiv 可以接受立即操作数。 AAM 可以,但只除 AL,而不是 AX,并将结果放在相反的寄存器中。但是,shr 是迄今为止更好的建议。 div 很慢。
    • 另外,mov ax, al 也不起作用。要进行零扩展,只需将 AH 设为零,或(386 及更高版本)movzx ax, al。要签名扩展,movsx ax,alcbw
    • 更好的网址是this one for idiv`
    • 感谢您的帮助!我真的很感激!
    猜你喜欢
    • 2019-02-07
    • 1970-01-01
    • 1970-01-01
    • 2013-01-14
    • 2022-11-29
    • 2012-06-19
    相关资源
    最近更新 更多