Умножение слов на языке ассемблера- программа кажется правильной, но не возвращает правильные ответы

#assembly #dos #tasm

#сборка #dos #tasm

Вопрос:

О боже… С чего мне вообще начать? Я БЕСЧИСЛЕННОЕ количество раз пытался получить простую программу, которая вычисляет площадь поверхности блока (всего за 4 или менее шагов умножения) и возвращает общую площадь. Я попытался определить программу так, чтобы основными переменными были слова, а затем снова были байты. но, несмотря ни на что, я продолжаю получать ответ, который не совпадает. моя программа не содержит ошибок или предупреждений, так что пока это хороший знак. Я пробовал умножение со знаком и без знака, но, похоже, ничего не работает. К сожалению, я не могу использовать двойные слова, поскольку у меня нет подходящего программного обеспечения. Ниже приведена моя программа:

 INCLUDE io.h

Cr        EQU  0DH       ; carriage return
Lf        EQU  0AH       ; line feed

TheStack  SEGMENT STACK
          DW   100H DUP (?)
TheStack  ENDS

Data      SEGMENT
a     Dw ?
b     Dw  ?
c     Dw  ?
d         Dw  ?
f         Dw  ?
g         Dw  ?
h         Dw  ?
e     dw   '2'
Int1      db   6 DUP (?), 0
Int2      db   6 DUP (?), 0
SUM       Db   6 DUP (?), 0
Int3      Db   6 DUP (?), 0
Prompt1   DB   'Please enter the height:  ', 0
Prompt2   DB   Cr, Lf, 'Enter the width:  ', 0
Prompt3   DB   Cr, Lf, 'Enter the length:  ', 0
String    DB   40 DUP (?)
Label1    DB   Cr, Lf, 'The sum is '
result1   DB   10 DUP (?), 0

Data      ENDS

Code      SEGMENT
          ASSUME Cs:Code, Ds:Data

Start:    Mov Ax, SEG Data    ; Load Data Segment Number.
          Mov Ds, Ax

Prompt:   Output Prompt1      ; Prompt for first number.
          Inputs String, 40   ; Read the ASCII characters.
          AToI String         ; Convert ASCII to Integer.
          Mov a, ax; Store first number.
          Output Prompt2      ; Prompt for second number.
          Inputs String, 40   
          AToI String
          Mov b, dx ; Store second number. 
          Mul dx; Add second number.
      mov d, ax
      itoa result1, ax
      output result1  
          Output Prompt3
      Inputs String, 40   
          AToI String
          Mov c, Dx ; Store second number
      Mul dx; Add second number.
      mov f, dx
      output f
      Mov b, dx
      Mov c, ax
      mul dx
      mov g, ax
      ATOI g
          mov g, ax
      ATOI f
          mov f, ax
      ATOI d
          mov d, ax
      add ax, f
      add ax, g
      mov h, ax
      output h
      AToI e
      mov e, ax
      mov h, dx
      mul dx
      itoa result1, ax
      output result1  


Quit:     Mov Al, 0           ; Put return code of zero in Al.
          Mov Ah, 4CH         ; Put DOS function call in Ah.
          int 21H             ; Call DOS

Code      ENDS
          END  Start
  

Я приношу извинения за плохие объяснения в коде, поскольку я скопировал его суть из предыдущей программы. теперь я не понимаю, как некоторые совершенно определенные переменные могут возвращать неправильные значения. Я даже изменил переменные, но мне все еще не повезло. Это и сбивает с толку, и раздражает. Чтобы представить это в перспективе, когда я пытаюсь умножить 1 на 1, возвращаемое значение равно 402, что далеко от истины! Я новичок в программировании на ассемблере, поэтому я действительно считаю, что частично это связано с неопытностью. Мой вопрос в том, как эта безошибочная программа в конечном итоге возвращает неправильные значения, когда она, казалось бы, собрана правильно и проверена множество раз на наличие ошибок? Есть ли недостающий фрагмент? Нужно ли мне полностью переписывать ее? Это ошибка эмулятора? Что не так с кодом, из-за чего кажущаяся идеальной программа работает неправильно?

Комментарии:

1. Используйте отладчик, чтобы вы могли выполнить один шаг через него и проверить регистры / память. Ваши ATOI , itoa или output функции сохраняют / восстанавливают DX? Я думаю, что вижу по крайней мере один случай, когда вы используете DX сразу после вызова output . В большинстве соглашений о вызовах DX не сохраняется при вызове. Вы не показываете код для них или не говорите, из какой библиотеки они взяты.

2. Если ваша программа считывает только два числа от пользователя, почему она вызывает ATOI более двух раз? Просто преобразуйте все в целое число сразу после прочтения. Тогда вы можете хранить данные в регистрах без кучи вызовов функций и загрузок / хранилищ между вашей математикой. (На современном процессоре цикл сохранения / перезагрузки в оба конца занимает около 5 циклов, что больше, чем умножение. Забота о количестве умножений в принципе не имеет значения по сравнению с количеством вещей, которые выполняет этот код : P)

3. Вы понимаете, что умножение двух 16-битных значений возвращает 32-битное значение, а умножение двух 8-битных значений возвращает 16-битное значение? Вероятно, вам следует внимательно ознакомиться с документацией для MUL и IMUL и убедиться, что вы случайно не оставляете данные.

Ответ №1:

из того, что я вижу, коробка имеет 6 сторон, по 2 с каждой стороны одинакового размера:

2 квадрата x на y
2 квадрата x на z
2 квадрата y на z
поверхность коробки является суммой всех

итак, все, что вам нужно, это:

сохраните введенные длины в [side_x], в [side_x] и [side_z]. Тогда вычисление суммы всех 3 пар квадратов могло бы выглядеть следующим образом (это практически оптимизировано)

 start: mov ax,[side_x]          ; side x*y
       mov bx,[side_y]
       mov dx,0
       mul bx
       shl ax,1                 ; 2 times
       mov [box_size],ax

       ;   2 sides x*z
       mov ax,[side_x]         
       mov bx,[side_z]
       mov dx,0
       mul bx 
       shl ax,1
       add ax,[box_size]
       mov [box_size],ax

       ;   2 sides y*z
       mov ax,[side_y]         
       mov bx,[side_z]
       mov dx,0
       mul bx
       shl ax,1
       add ax,[box_size]
       mov [box_size],ax
  

затем распечатайте [box_size] и готово

примечание: конечно, это работает только тогда, когда размер поля соответствует 16-разрядному регистру (< 65536), поэтому «верхняя часть» умножения (в dx) игнорируется

Комментарии:

1. Я пробовал это, и даже после этого я все еще не получаю возвращенного правильного значения. Предполагается, что я запрашиваю у пользователя размеры, а затем умножаю их. Я даже не уверен, что я делаю неправильно! У меня такое чувство, что я просто бегаю по кругу.

2. к черту это, я просто попробовал это с заранее определенными переменными, и это работает. но не с переменными, которые я хочу определить через приглашение. Странно. Интересно, что я делаю не так.

3. ага! Выяснил, что я сделал не так! Это было прямо у меня под носом! Я ввел третье приглашение слишком рано. Итак, почему, черт возьми, я это пропустил? лол

4. нет, подождите, неважно, что они все еще были предопределены. Выстрел… Похоже, что dosbox является большой проблемой без всякой причины. Я поместил следующее перед каждой новой стороной:

5. вывод prompt3 Вводит строку, 40 ; Считывает символы ASCII. Строка AToI