【问题标题】:Calculate absolute difference |A-B| in assembly using only INC, DEC, JNZ, HALT - interview question计算绝对差值 |A-B|仅使用 INC、DEC、JNZ、HALT 进行组装 - 面试问题
【发布时间】:2020-05-31 15:53:23
【问题描述】:

这是我在面试中遇到的一个问题,我没有找到解决方案 - 所以我尝试自己解决。
我们可以在这里使用伪代码——它不需要是正式的代码。

问题是得到无符号输入的绝对差:

假设您的汇编语言仅包含以下指令:incdecjnzhalthalt = 停止运行)。

任务:AB 是保存非负值的寄存器。 程序应计算|A-B| 的值并将结果定位到C。此外,该语言还拥有寄存器CD、...、Z,您可以假设它们在程序启动时被初始化为零。

这是我的尝试,我的主要想法是减少两个寄存器直到一个变为零,然后将另一个寄存器的值移动到C

// zero case handling
dec a
inc a
jnz a_pre_loop_not_zero // a != 0
// a == 0, check if b == 0
dec b
inc b
jnz move_b_to_c // a == 0, b !=0 
// a == 0 , b == 0 -> c needs to be 0
halt  

a_pre_loop_not_zero:
  dec b
  inc b
  jnz main_loop // a != 0, b != 0

// a != 0 , b == 0
move_a_to_c:
    inc c
    dec a
    jnz move_a_to_c
    halt  

// a,b != 0
main_loop:
  dec b
  jnz b_not_zero // b!=0
  // b became zero before a -> a contains result+1 now
  dec a
  jnz move_a_to_c
  halt // if a == 0 now -> a == b -> c needs to be 0

  b_not_zero:
      dec a
      jnz main_loop // a != 0

  // a became zero before b -> b contains the result now
  move_b_to_c:
    inc c
    dec b
    jnz move_b_to_c
    halt              

现在,我认为它可以工作 - 但它看起来很脏。
更具体地说,我认为零案例处理可以用更干净的方式完成,也许我们甚至可以在主循环中考虑它(无需在预循环代码中检查它)。
另外,我没有使用寄存器CD、...、Z 被初始化为 0 并且可以使用的事实——这让我怀疑也许有更好的方法。

这个问题有更好的解决方案吗?

【问题讨论】:

  • 你的方法看起来不错。我可能会考虑通过增加它们来跳过零处理,然后直接进入主循环。
  • @ErikEidt:如果我们也有 JZ,这将很容易; do { if(--a == 0) break; } while(--b); 但是我们可以通过一个在循环开始时为零的寄存器的虚拟 INC/JNZ 从一个 JNZ 合成一个 JZ。或非零寄存器的inc/dec/jnz。
  • 我投票结束这个问题,因为它是代码高尔夫而不是实际的编程问题。

标签: algorithm assembly pseudocode


【解决方案1】:

现在,我认为它可以工作 - 但它看起来很脏。

您可以通过编写更多汇编方式来改善它的外观:

    dec A                   // zero case handling
    inc A
    jnz A_pre_loop_not_zero // A != 0
    dec B                   // A == 0, check if B == 0
    inc B
    jnz move_B_to_C         // A == 0, B !=0 
    halt                    // A == 0, B == 0 -> C needs to be 0
A_pre_loop_not_zero:
    dec B
    inc B
    jnz main_loop           // A != 0, B != 0

move_A_to_C:                // A != 0, B == 0
    inc C
    dec A
    jnz move_A_to_C
    halt  
main_loop:                  // A,B != 0
    dec B
    jnz B_not_zero          // B != 0
    dec A                   // B became zero before A -> A contains result+1 now
    jnz move_A_to_C
    halt                    // if A == 0 now -> A == B -> C needs to be 0
B_not_zero:
    dec A
    jnz main_loop           // a != 0
move_B_to_C:                // a became zero before b -> b contains the result now
    inc c
    dec B
    jnz move_B_to_C
    halt              

suggestion by Eric Eidt 预先递增 AB 会远离可能的零。
我认为我们可以假设incdec 都使用环绕逻辑。如果不是 AB 上的这些增量将是错误的!

    inc     A
    inc     B

L1: dec     A
    jnz     L4

L2: dec     B
    jnz     L3
    halt
L3: inc     C      ; A == 0 -> C = B
    jnz     L2     ; (*)

L4: dec     B
    jnz     L1

L5: inc     C      ; B == 0 -> C = A
    dec     A
    jnz     L5
    halt

增加C 寄存器永远不会产生零。因此标有星号的条件跳转总是会跳转。这减少了 2 条指令。

也许有点老派,但绝对好看……

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-07-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多