使用ONLY inc dec和jnz命令实现c = a * b

时间:2012-10-14 10:42:26

标签: assembly

在我的一次采访中,我在一个'新的'原始集合中遇到了一个非常复杂的问题(当他们告诉我他们基于Python的QA测试时,为什么地狱QA需要汇编知识?),这是是这样的:

假设您的汇编语言仅包含以下说明:

  • 'inc REG' :将给定的寄存器增加一个。
  • 'dec REG' :将给定的寄存器减1。
  • 'jnz LABEL' :如果前一条指令的结果不为零,则跳转到给定的LABEL。
  • 'HELT' :停止运行。

任务:A和B寄存器保持非负值。 程序应该计算A * B的值并将结果定位在C. 此外,该语言包含寄存器C,D,...,Z,您可以假设它们在程序开始时被初始化为零。

这里有几点需要更多的关注,比如你必须事先考虑A和\或B值可能为零..并且多个零是......零...这是该死的...

P.S。由于这个问题,我没有达到'my_atoi()'问题的实现......: - (

谢谢!

4 个答案:

答案 0 :(得分:5)

我不打算给出完整的答案,但关键是你必须自己定义一个mov程序。假设dec X X保持为0会产生负数(或非常大),可以这样做:

MOV_AD:     ; copy value in A to D, using E as scratch space
    inc A   ; must be non-zero for jnz to work below
COPYLOOP:
    inc D
    inc E
    dec A
    jnz COPYLOOP
    dec D   ; undo the first inc A in D

            ; E now contains the initial value of A + 1
MOVBACK:    ; move value in E back to A
    inc A
    dec E
    jnz MOVBACK
    dec A   ; undo the first inc A

WIPE_E:     ; wipe the scratch space
    dec E
    jnz WIPE_E

一旦有了适当的mov例程,就可以将重复增量和乘法实现为重复加法。在两者中,您需要使用inc技巧才能使jnz起作用,并且在乘法例程中,您需要以减法结束。

答案 1 :(得分:3)

逐步打破这一步:

原件:

C = A * B

相当于:

C = 0
while A != 0:
   dec A
   C += B

相当于:

C = 0
while A != 0:
   dec A
   # Note: Following block of code changes B but sets it back to
   #       original value when done
   Z = 0
   while B != 0:
       dec B
       inc Z
       inc C
   B = Z

相当于:

C = 0
Z = 0
while A != 0:
   dec A
   # Note: Following block of code changes B but sets it back to
   #       original value when done
   while B != 0:
       dec B
       inc Z
       inc C
   while Z != 0:
       dec Z
       inc B

现在我们只需要弄清楚如何翻译这个结构:

while LOOP_VAR != 0:
    dec LOOP_VAR
    ... some code here which does not use LOOP_VAR ...

可以翻译为:

    # Next 4 lines do "if LOOP_VAR == 0: goto loop_end"
    inc LOOP_VAR
    dec LOOP_VAR  # To set flags
    jnz loop_again
    goto loop_end
loop_again:
    ... some code here which does not use LOOP_VAR ...
    dec LOOP_VAR
    jnz loop_again
loop_end:

当然,我们需要将无条件转换为条件转换。幸运的是,我们有许多已知为零的变量,因此我们可以测试其中一个变量是否为零:

    # Unconditional jump to "loop_end".  Note that Q is always zero.
    inc Q
    dec Q
    jnz loop_end

所以,把所有这些放在一起:

    # Next 3 lines do "if A != 0: goto outer_loop_again"
    inc A
    dec A  # To set flags
    jnz outer_loop_again

    # Unconditional jump to "outer_loop_end".  Note that Q is always zero.
    inc Q
    dec Q
    jnz outer_loop_end

outer_loop_again:

    # Next 3 lines do "if B != 0: goto addition_loop_again"
    inc B
    dec B  # To set flags
    jnz addition_loop_again

    # Unconditional jump to "addition_loop_end".  Note that Q is always zero.
    inc Q
    dec Q
    jnz addition_loop_end

addition_loop_again:
    inc Z
    inc C
    dec B
    jnz addition_loop_again
addition_loop_end:

    # Next 3 lines do "if Z != 0: goto move_loop_again"
    inc Z
    dec Z  # To set flags
    jnz move_loop_again

    # Unconditional jump to "move_loop_end".  Note that Q is always zero.
    inc Q
    dec Q
    jnz move_loop_end

move_loop_again:
    inc B
    dec Z
    jnz move_loop_again
move_loop_end:

    dec A
    jnz outer_loop_again
outer_loop_end:

    # Finished!
    helt

编辑补充:实际上,有一种稍微简单的方法。我们可以在开始时检查A或B是否为零,这简化为:

    # Check if A is zero, and halt if so
    # (So that multiplying by zero gives zero)
    inc A
    dec A  # To set flags
    jnz a_non_zero
    helt  # Multiplying by zero gives zero
a_non_zero:

    # Check if B is zero, and halt if so
    # (So that multiplying by zero gives zero)
    inc B
    dec B  # To set flags
    jnz b_non_zero
    helt  # Multiplying by zero gives zero
b_non_zero:

outer_loop_again:

addition_loop_again:
    inc Z
    inc C
    dec B
    jnz addition_loop_again

move_loop_again:
    inc B
    dec Z
    jnz move_loop_again

    dec A
    jnz outer_loop_again

    # Finished!
    helt

答案 2 :(得分:2)

JNZ 指令可以看作 做..而 结构,{{3代码:

@_loop1:        ;   do {
                ;       do {
    INC Z       ;           z++;
    INC C       ;           c++;
    DEC B       ;           b--;
    JNZ _loop1  ;       } while (b != 0);
                ;       
@_loop2:        ;       do {
    INC B       ;           b++;
    DEC Z       ;           z--;
    JNZ _loop2  ;       while (z != 0);
                ;       
    DEC A       ;       a--;
    JNZ _loop1  ;   } while (a != 0);

答案 3 :(得分:0)

我刚刚在JJ面试中完成了这项任务。这似乎是正确的解决方案。如果我错了请纠正我

INC A
DEC A
JNZ L0
HELT

L0:
INC B
DEC B
JNZ L1
HELT

L1:
INC C
INC D
DEC A
JNZ L1
DEC B
JNZ L2
HELT

L2:
INC C
INC A
DEC D
JNZ L2
DEC B
JNZ L1
HELT