如何循环和编码为二进制?

问题描述

我正在尝试在LMC中运行一个将任何数字转换为二进制的程序。

通常我只会使用除法,但由于Little Man Computer不允许除法或乘法,所以我不能这样做。我在这方面获得的最大成果只是一个简单的INP在这个阶段,我不知道如何开始循环,甚至不知道如何开始。

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

例如:我输入33,它的输出为100 001。

我是一个初学者。我今天才拿起它,因此将其保持简单将不胜感激。

解决方法

您写道,对于33,输出应为100001。这可能不起作用(取决于LMC仿真器),因为第二个值可以在不带前置零的情况下输出,因此它将显示为1001。可以是令人困惑,因为它看起来很像您对输入9的期望。

我建议将每个二进制数字作为一个单独的数字输出:这样,您可以确保在输出中显示所有 个数字。

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

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

    a。输出1,然后从 n 中减去512,否则:

    b。输出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,则输出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的幂。为此,您可以将修改后的代码与引用最低功率2的固定代码段(也是SUB,但从未执行)进行比较。

以下是此想法的实现:

#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>