Неверное значение переменной an, в которой хранится LCM двух чисел (программа 8086)

Ниже приведен код, который я написал для поиска LCM из двух чисел в EMU8086. Когда я запустил его, я получаю значение 0 в переменной Ans.

.MODEL SMALL 
.DATA 
Num1 DW 250 
Num2 DW 100
Ans DW ? 
.CODE 
MOV AX,@DATA 
MOV DS, AX 
MOV AX, Num1 
MOV BX, Num2 
MOV DX, 0000h 
NEXT: PUSH AX 
PUSH DX 
DIV BX 
CMP DX, 0000h 
JZ LAST 
POP DX 
POP AX 
ADD AX, Num1 
JNC NEXT 
INC DX 
JMP NEXT 
LAST: POP Ans+2 
POP Ans 
MOV AH, 4Ch 
INT 21h 
END

person havegudday    schedule 07.11.2020    source источник
comment
Интересно, связано ли это с это? emu8086, кажется, имеет ошибку в реализации DIV. Вы тестировали с другими эмуляторами?   -  person Nate Eldredge    schedule 07.11.2020
comment
Однако одно замечание; Я не внимательно прочитал код, но, похоже, вы сохраняете два слова результата в Ans и Ans+2. Однако Ans имеет только одно выделенное слово, поэтому pop Ans+2 собирается перезаписать что-то еще. Не уверен, что это ваша ошибка, но выглядит неправильно.   -  person Nate Eldredge    schedule 07.11.2020
comment
Кроме того, это довольно абсурдный алгоритм поиска LCM; многократно добавляя Num1 к себе, пока оно не станет кратным Num2. Вы можете поискать что-то более эффективное в алгоритме Евклида.   -  person Nate Eldredge    schedule 07.11.2020


Ответы (1)


НОК (а, б) = а * б / НОД (а, б)

Благодаря этому уравнению вы можете найти НОД, используя алгоритм Евклида, а затем вычислить НОК. Предполагая, что числа a и b находятся в al и dl, этот код вычисляет LCM.

; Save multiplication value
MOV AL, DL ; This 2 lines is AL * DH
MUL DH
PUSH AX ; Store result in stack

FINDBCD: ; General idea is : LCM(a, b) = a*b/BCD(a,b)
    ; We calculate BCD with euclidean algorithm
    CMP DH, DL
    JNS CALCULATE ; Jump if DL < DH else swap them
    MOV CL, DL ; This 3 line swap DL and DH
    MOV DL, DH
    MOV DH, CL
    CALCULATE:
    MOV AL, DH ; Move greater number in AL
    XOR AH, AH ; Zero AX 8 second bits
    DIV DL ; This is AL/DL
    CMP AH, 0 ; If remainder is zero so we found BCD
    JE AFTERFINDBCD
    SUB DH, DL ; Else substract smaller number from greater number
    JMP FINDBCD ; Do this until find BCD

AFTERFINDBCD:
    CMP DH, DL 
    JNS FINDLCM ; Jump if DL < DH
    MOV CL, DL ; This 3 line swap DL and DH
    MOV DL, DH
    MOV DH, CL

FINDLCM:
    POP AX ; Retreive multiplication result
    DIV DL ; This is AX/DL
    AND AX, 0000000011111111B ; Ignore remainder

person parsa2820    schedule 17.11.2020
comment
Это занимает два 8-битных входа. Вопрос имеет 16-битные входные данные, поэтому LCM потенциально больше 16-битного. Как Бретт Хейл указал на связанный вопрос, вы можете сделать (a / gcd) * b, чтобы вы может заканчиваться расширением mul, потому что a по определению делится на НОД. См. ответ Бретта на этот связанный вопрос; то же самое с 16-битными регистрами должно работать для OP. - person Peter Cordes; 17.11.2020
comment
Если вы действительно хотите поменять местами DL и DH, не оставляя копии где-либо еще, xchg dh,dl по крайней мере так же эффективен почти на всех процессорах, гораздо эффективнее на реальном 8086. Кроме того, and ax, 0x00ff глупо: используйте mov ah,0 или xor ah,ah, как вы делали ранее. - person Peter Cordes; 17.11.2020
comment
CMP / JNS не определяет, какой из них больше. Вы хотите ja для беззнакового выше. Условие ns просто проверяет MSB результата вычитания, что работает только в том случае, если числа были маленькими или близкими при интерпретации как целые числа со знаком (и переполнения со знаком не произошло). Вы используете неподписанный div, поэтому вы должны использовать неподписанные условия перехода. - person Peter Cordes; 17.11.2020
comment
Обратите внимание, что стандартному GCD требуется только 2 mov инструкции в цикле: Наибольший общий делитель - person Peter Cordes; 17.11.2020
comment
Спасибо за ваши комментарии, я не использовал ассемблер профессионально, и я фактически не знал большинство из них сам. - person parsa2820; 18.11.2020
comment
Вы по-прежнему можете отредактировать свой ответ, чтобы исправить ошибку jns и любые другие улучшения, которые вы хотите внести. И отметить, что он обрабатывает только 8-битные входы. - person Peter Cordes; 18.11.2020