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.

Другие вопросы по тегам