我试图让一个程序在 LMC 中运行,将任何数字转换为二进制。
通常我只会使用除法,但我不能这样做,因为小人电脑不允许除法或乘法。我在这方面得到的最远的只是一个简单的INP
. 在这个阶段,我不知道如何开始循环,甚至如何开始。
如何开始循环?我该如何阻止他们?我会以某种方式需要一个重复循环来减去一个值,直到它达到 1 或 0。这将实现我的目标,因为我可以输出它。
例如:我输入 33,它在输出中给出 100 001。
我是一个完全的初学者。我今天刚刚拿起它,所以保持简单将不胜感激。
我试图让一个程序在 LMC 中运行,将任何数字转换为二进制。
通常我只会使用除法,但我不能这样做,因为小人电脑不允许除法或乘法。我在这方面得到的最远的只是一个简单的INP
. 在这个阶段,我不知道如何开始循环,甚至如何开始。
如何开始循环?我该如何阻止他们?我会以某种方式需要一个重复循环来减去一个值,直到它达到 1 或 0。这将实现我的目标,因为我可以输出它。
例如:我输入 33,它在输出中给出 100 001。
我是一个完全的初学者。我今天刚刚拿起它,所以保持简单将不胜感激。
你写的是 33 的输出应该是 100 001。这可能不起作用(取决于 LMC 模拟器),因为第二个值可以在没有预先添加的零的情况下输出,因此它会显示 100 1。这可能会令人困惑,因为它看起来很像您对输入 9 的期望。
我建议将每个二进制数字输出为一个单独的数字:这样可以确保所有数字在输出中都是可见的。
像这样对输入n进行编码的算法可能如下:
将n与 512 进行比较。如果不小于:
一个。输出 1,并从n中减去 512 ,否则:
湾。输出 0
将n的值加倍,即将n添加到自身
再重复以上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>