首页 > 解决方案 > 如何循环和编码为二进制?

问题描述

我试图让一个程序在 LMC 中运行,将任何数字转换为二进制。

通常我只会使用除法,但我不能这样做,因为小人电脑不允许除法或乘法。我在这方面得到的最远的只是一个简单的INP. 在这个阶段,我不知道如何开始循环,甚至如何开始。

如何开始循环?我该如何阻止他们?我会以某种方式需要一个重复循环来减去一个值,直到它达到 1 或 0。这将实现我的目标,因为我可以输出它。

例如:我输入 33,它在输出中给出 100 001。

我是一个完全的初学者。我今天刚刚拿起它,所以保持简单将不胜感激。

标签: little-man-computer

解决方案


你写的是 33 的输出应该是 100 001。这可能不起作用(取决于 LMC 模拟器),因为第二个值可以在没有预先添加的零的情况下输出,因此它会显示 100 1。这可能会令人困惑,因为它看起来很像您对输入 9 的期望。

我建议将每个二进制数字输出为一个单独的数字:这样可以确保所有数字在输出中都是可见的。

像这样对输入n进行编码的算法可能如下:

  1. n与 512 进行比较。如果不小于:

    一个。输出 1,并从n中减去 512 ,否则:

    湾。输出 0

  2. 将n的值加倍,即将n添加到自身

  3. 再重复以上9次。递减一个以 10 开头的计数器,只要它不设置负标志就重复。

如何循环

因此,您以静态方式“启动”循环:在DAT指令中设置计数器的初始值。在上述算法中,我们希望计数器从 10 开始:

COUNTER DAT 10

然后当你需要循环时,递减计数器:

LDA COUNTER
SUB ONE
STA COUNTER

而且(像许多 LMC 程序一样),您需要一个常量ONE

ONE DAT 1

最后,要知道计数器是否没有低于 0,可以检查“负”标志。这是一个可以由 设置的标志SUB,当存在负溢出时(请记住,LMC 不能真正存储负值,因此您只有标志作为指示)。指令(当BRP为正时分支)将使用该标志来决定是否跳转:

BRP LOOP

LOOP应该是循环代码开始位置的标签。

执行

请注意,在这个实际案例中,执行此循环超过 10 次是没有用的,因为 LMC 中的输入不能超过 999,在二进制中需要 10 位。

下面是上述算法的实现,还需要注意的是,即使程序计数器在第一次执行后重置,计数器也会从初始值开始:

#input:13
         INP
         STA NUM
         LDA NINE
LOOP     STA COUNTER
         LDA NUM
COMPARE  SUB POW_9
         BRP BIT1
BIT0     LDA ZERO
         OUT
         BRA DOUBLE
BIT1     STA NUM  ; Reduce number with 512
         LDA ONE
         OUT
DOUBLE   LDA NUM
         ADD NUM
         STA NUM
         LDA COUNTER
         SUB ONE
         BRP LOOP
ZERO     HLT
POW_9    DAT 512
ONE      DAT   1
NINE     DAT   9
NUM      DAT
COUNTER  DAT

<script src="https://cdn.jsdelivr.net/gh/trincot/lmc@v0.7/lmc.js"></script>

选择

还有其他几种方法可以完成此任务。例如,我们可以硬编码 10 个二进制数字所需的 2 的幂:1、2、4、...、512。

然后将输入值与其中最大值(2 9 = 512)进行比较。如果不小于,则输出 1 位,否则输出 0。如果为 1,则从输入数中减去 2 的幂。在这两种情况下,切换到之前的 2 次方 (2 8 ) 并重复此过程。重复此操作,直到完成 2 0的工作。

你可以尝试在没有循环的情况下实现它,但是你将拥有 10 次相同的代码,只是 2 的幂次方不同。这甚至可能是一个挑战,以适应 LMC 的 100 个“邮箱”的内存(它会工作但是,如果您将输入限制为 64,那么您只需要 6 个二进制数字)。

要使用循环(更少的代码)来实现这一点,您可以使用间接寻址技术。在 LMC 中没有用于间接寻址的指令,但使用自修改代码是可能的。

假设您有如下实施的权力列表:

POW_9   DAT 512
POW_8   DAT 256
; ... etc
POW_0   DAT 1

然后,您将通过以下方式将累加器与 POW_9 进行比较:

COMPARE SUB POW_9

标签允许我们在那里存储不同的指令,以便下次执行时它实际上执行以下操作:

COMPARE SUB POW_8

这可以通过以下操作实现:

LDA COMPARE
ADD ONE
STA COMPARE

这有点棘手,因为代码被视为数据,这会修改代码。请注意更改SUB POW_9实际上是如何工作的,就好像您引用数组中的元素并增加该数组中的索引一样。

您需要有一个停止条件,这样您就不会使代码引用不在您的DAT列表中的 2 的幂。SUB为此,您可以将修改后的代码与引用 2 的最低幂的固定代码(也是 a ,但从未执行)进行比较。

这是这个想法的一个实现:

#input:13
         INP
         STA NUM
         LDA FIRST
LOOP     STA COMPARE ; self-modifying code!
         SUB LAST    ; Compare with "SUB ZERO"
         BRP ZERO  
         LDA NUM
COMPARE  SUB POW_9 ; Indirect addressing
         BRP BIT1
BIT0     LDA ZERO
         OUT
         BRA NEXT
BIT1     STA NUM  ; Reduce number with power
         LDA ONE
         OUT
NEXT     LDA COMPARE ; Change power of 2
         ADD ONE
         BRA LOOP
FIRST    SUB POW_9  ; Never executed
LAST     SUB ZERO   ; Never executed
POW_9    DAT 512
POW_8    DAT 256
POW_7    DAT 128
POW_6    DAT  64
POW_5    DAT  32
POW_4    DAT  16
POW_3    DAT   8
POW_2    DAT   4
POW_1    DAT   2
ONE      DAT   1
ZERO     HLT
NUM      DAT

<script src="https://cdn.jsdelivr.net/gh/trincot/lmc@v0.7/lmc.js"></script>


推荐阅读