2017-02-01 3 views
0

В целях обучения я пытаюсь написать любое целочисленное деление в MARIE.MARIE ASM Lang - деление на целые числа (положительные/отрицательные)

Это стандартный (надеюсь, правильный) код, который делит 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 

Как я могу заставить его работать на негативы? Возможно, некоторые IFs и некоторая битовая маска, возможно, но я не уверен, как это сделать.

ответ

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 CPU знак остатка 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.

Смежные вопросы