MARIE ASM Lang - деление на целые числа (положительное / отрицательное)
В целях обучения я пытаюсь написать любое целочисленное деление в MARIE.
Это стандартный (надеюсь, правильный) код, который делит X на Y с остатком, но только с положительными целыми числами.
LOAD X
STORE REMAIN
WHILE SUBT Y
SKIPCOND 800
JUMP CHECK
DO STORE REMAIN
LOAD RESULT
ADD ONE
STORE RESULT
LOAD REMAIN
JUMP WHILE
CHECK SKIPCOND 400
JUMP END
STORE REMAIN
LOAD RESULT
ADD ONE
STORE RESULT
END HALT
X HEX XXXX
Y HEX YYYY
RESULT HEX 0000
REMAIN HEX 0000
ONE HEX 0001
Как я могу заставить это работать на негативы? Возможно, некоторые IF и битовая маска, но я не уверен, как это сделать правильно.
1 ответ
Зависит от того, как вы это определяете... D/d=[q,r]
(Дивиденд / делитель = [частное, остаток])
- 5/2 = [2,1] (у вас есть этот)
- -5 / -2 = [3, 1] или [2, -1] (способ x86)
- 5 / -2 = [-2, 1] (x86) или [-3, -1]
- -5/2 = [-3,1] или [-2, -1] (x86)
(На процессоре x86 знак остатка r
всегда совпадает с признаком дивидендов D
)
Если вы посмотрите на результаты выше, в каждом случае абсолютные значения одинаковы:
- | 5 | / | 2 | = [| 2 |, | 1 |]
Остаток имеет знак дивиденда, частное имеет знак делителя XOR делитель ([+, +] == [-, -] ==
+ против [+, -] == [-, +] ==
-).
Таким образом, вы можете добавить в начале своей процедуры подготовительную часть, которая будет проверять каждое значение, и отмечать в некотором флаге, было ли оно положительным или отрицательным, преобразовывать его в положительное, выполнять деление, а затем в текущий момент. END
исправьте результаты с помощью флагов.
Нечто подобное (это мой первый раз с Marie Assembly, так что воспринимайте это скорее как подсказку и исправляйте ее в случае необходимости, надеюсь, только с синтаксисом, но, может быть, даже логические ошибки могут быть, я не проверял, работает ли код!)
CLEAR
/ init temporary/result variables to zero
STORE q_flag
STORE r_flag
STORE RESULT
SUBT X / try (-Dividend) value
SKIPCOND 800
JUMP DividendWasPositive / positive or zero
STORE X / (-Dividend) positive, rewrite original X
STORE q_flag / set flags to positive value (X)
STORE r_flag
DividendWasPositive,
CLEAR
SUBT Y / try (-divisor) value
SKIPCOND 400
JUMP DivisorNotZero
HALT / division by zero detected, error
DivisorNotZero,
SKIPCOND 800
JUMP DivisorWasPositive
STORE Y / (-divisor) positive, rewrite original Y
/ flip quotient flag value (zero <-> nonzero) ("nonzero" == X)
LOAD X / will not "flip" anything when 0 == X
SUBT q_flag / but then q = 0, so it's harmless deficiency
STORE q_flag / q_flag is now zero or positive (X) value
DivisorWasPositive,
/ here X and Y contain absolute value of input numbers
/ q_flag is positive value when quotient has to be negated
/ r_flag is positive value when remainder has to be negated
/ .. do your division here ..
/ patching results by the q/r flags from the prologue part
AdjustQuotientSign,
LOAD q_flag
SKIPCOND 800
JUMP AdjustRemainderSign
CLEAR
SUBT RESULT
STORE RESULT / quotient = -quotient
AdjustRemainderSign,
LOAD r_flag
SKIPCOND 800
JUMP SignsAdjusted
CLEAR
SUBT REMAIN
STORE REMAIN / remainder = -remainder
SignsAdjusted,
HALT
q_flag, DEC 0
r_flag, DEC 0
... rest of your variables
Другой вариант может заключаться в том, чтобы иметь отдельные варианты подпрограммы для каждой ситуации (4 варианта), так как они будут различаться только в ADD/SUBT Y/ONE и в состоянии завершения 000 против 800, что будет выполнять меньше инструкций для каждого случая (лучшая производительность), но было бы немного больше строк кода, плюс приведенный выше код может дать вам несколько новых идей о том, как работать в Assembly.