assembly LMC -十进制到二进制,带休止符

3phpmpom  于 2023-10-19  发布在  其他
关注(0)|答案(2)|浏览(96)

我正在为一个挑战写一个程序的小人电脑:
这个程序应该接受一个十进制数作为输入,并输出等价的二进制数.它应该重复地将输入除以2,然后输出二进制数。
例如,如果输入是8,机器应该将8除以2并输出0。然后,它应该将4除以2并输出0。接下来,它应该将2除以2并输出0。最后,它应该将1除以2并输出1。
下面是我的代码:

INP
         STA NUM
         LDA 0
         STA REMAIN

LOOP     LDA NUM
         SUB TWO
         BRP CONTINUE
         BRA END

CONTINUE LDA REMAIN
         ADD ONE
         STA REMAIN
         BRA LOOP

END      LDA REMAIN
         OUT
         HLT

NUM      DAT
REMAIN   DAT
ONE      DAT 1
TWO      DAT 2

问题

当我用输入8运行这个程序时,它一直在循环。当调试时,我看到REMAIN没有像我预期的那样初始化为0,而是初始化为901。那么我还是不明白为什么这会导致一个无限循环,因为我反复减去2,在某个点上,这会导致一个负数。但不知何故,这种情况从来没有发生过。
我错在哪里?

svmlkihl

svmlkihl1#

您已经描述了一个算法,该算法将以二进制表示形式输出一个数字,反转(!)。我会假设这是你想要实现的。
在您的尝试中有几个问题:

  • LDA 0将加载邮箱0中的值,这不是您想要的。相反,将邮箱标记为ZERO并将其初始化为值0,然后执行LDA ZERO
  • REMAIN是一个误导性的名称,因为您的代码不会在那里存储余数,而是除以2的商。余数是重复减去2后在NUM中剩余的部分。我会使用标签QUOTIENTHALF代替。
  • 相关:REMAIN的最终输出不是余数,而是商。由于只想输出0或1,因此输出应该依赖于NUM,而不是REMAIN
  • 你的循环永远不会更新NUM,所以用2相减的结果会丢失,循环的下一次迭代将从NUM的原始值重新开始,并再次做完全相同的事情,当NUM为2或更大时,会导致无限循环。在CONTINUE标签上应该有一个STA NUM
  • NUM是奇数或偶数的情况之间没有区别。唯一被捕获的事件是当减法导致负溢出时,但此时您不知道是输出0还是1。您应该添加一条BRZ指令来检测NUM为零的情况,这样您就知道需要输出0。另一种情况,当输出1时,将由负溢出识别。
  • 您的程序只预见到输出 * 一次 *,但您希望潜在地输出多个数字(全部为0或1)。所以应该有另一个循环,它取商(原始NUM值的一半)并将其用作NUM来重复整个过程。这应该继续下去,直到商为零。

下面是你的代码,其中考虑了所有这些注解:

#input: 41
          INP

CALCULATE STA NUM
          LDA ZERO
          STA HALF # This is not the remainder, but quotient

LOOP      LDA NUM
          BRZ OUTPUT # Detect when to output a zero
          SUB TWO
          BRP CONTINUE

OUTPUT    LDA NUM # output the remainder
          OUT
          LDA HALF # now work with quotient
          BRZ END
          BRA CALCULATE # ... and repeat a division by 2

CONTINUE  STA NUM # Save before continuing
          LDA HALF
          ADD ONE
          STA HALF
          BRA LOOP

END       HLT

NUM       DAT
HALF      DAT
ZERO      DAT 0
ONE       DAT 1
TWO       DAT 2

<script src="https://cdn.jsdelivr.net/gh/trincot/[email protected]/lmc.js"></script>

你可以在这里运行它。它将默认为输入41(作为示例),其输出将为:
同样,这是 * 反向 * 二进制,所以0 b101001,即。32 + 8 + 1
最后一点,这不是最有效的算法,因为减法的次数将是𝑛/2 +𝑛/4 +𝑛/8 +...= O(𝑛)。𝑛如果你使用2的幂减法,而不是总是2,这可以在O(log)的时间复杂度内完成。这将以更复杂的程序为代价。

piwo6bdm

piwo6bdm2#

这里有一些关于你发布的代码的基本提示。

  • LDA 0不做你想做的事:它将0视为地址,因此从存储器位置0加载(实际上存储代码而不是数据;这里它保存第一个指令INP,其值为901,因此def不是0。您需要使用值为0的基准面,就像SUB TWO-LDA ZERO一样,并与其他常量一起沿着定义ZERO DAT 0
  • 要持久地从NUM中减去,需要一个加载-减去-* 存储 * 序列。由于您没有存储回NUMNUM永远不会改变-因此在load & subtract之后放置一个STA NUM,就像使用REMAIN一样
  • (顺便说一句,计算除数可以从被除数中减去的次数的方法(在更新的被除数<= 0之前)* 计算商 *-一个 * 余数**是 * 当除数不能再从更新的被除数中减去时,更新的被除数中剩下的东西 *)。

此外,本发明还

  • 学习如何使用调试器,并观察什么时候有些东西不像你期望的那样工作。你可以问一些关于调试的问题,如果它们足够具体的话。单步并观察每一行的效果;如果有什么意外发生,这就是我们要关注的在这里,如果你单步执行,你可能已经注意到LDA 0没有将0加载到累加器中,而是901 -所以只有3条指令进入程序,我们有一些意想不到的事情。
  • 当你在这里问一个问题时,试着用你自己的话问一个问题,并具体说明你的代码的哪一部分出现了故障,或者你不理解什么。像“你能写这个程序吗”这样的问题在这里太笼统了。我们不是为你写代码,而是帮助你克服困难,这样你就可以继续你的项目。为了让它工作得更好,你必须(a)自己尝试,(B)给予我们一个你卡住的地方的指示。

相关问题