由于 LMC 可用的内存有限,该程序在输入值 69 以上发生故障。可能的最高地址(邮箱)是 99。
此代码使用筛子的内存空间,筛子需要与您给它的输入一样大。筛子的内存从邮箱 31 开始,该邮箱在标签LDINS
和STINS
代码中定义: 531 表示LDA 31
,其中 31 是邮箱地址。同样 331 表示STA 31
。这定义了筛子的最大尺寸:31 到 99 给出了总共 69 个可用于筛子的邮箱。
该指令STA WRINS
将动态更改标签处的代码,WRINS
以便在筛子数组中写入一个值。写入的动态操作码是 300 + 31 + [一些动态偏移]。300 代表STA
, 31 是筛子阵列的起点。现在当偏移量为69以上时,这条指令就变成了400以上,不再代表一条STA
指令,而是一个未定义的操作码。
你可以在下面的代码片段中运行你的代码,当你给它 70 作为输入时,你会看到它停在那个指令上,说操作码是无效的:
#input: 70
INP
STA INPUT
LDA C
OUT
ADD ONE
OUT
LOOP LDA A \\ first loop
ADD ONE
STA A
SUB INPUT
BRP END
LDA A
ADD LDINS
STA READINS
READINS DAT
BRZ PRIME
BRA LOOP
PRIME LDA A
OUT
STA B
WRITELOOP LDA B \\ second loop
SUB INPUT
BRP LOOP
LDA B \\ at this moment program breakdown when input is more than 69
ADD STINS
STA WRINS
LDA A
WRINS DAT
LDA B
ADD A
STA B
BRA WRITELOOP
END HLT
INPUT DAT 0
LDINS DAT 531 \\ this is working, but i think i might do a better code
STINS DAT 331
A DAT 1
ONE DAT 1
B DAT
C DAT 2
<script src="https://cdn.jsdelivr.net/gh/trincot/lmc@v0.76/lmc.js"></script>
所以结论是,这种行为实际上并不是程序中的错误,而更多的是 LMC 的内存限制。埃拉托色尼筛子的 LMC 实现总是在该大小附近有一个限制,这取决于您可以使代码多么简洁——为数组留出空间。
关于代码的备注
以上回答了您的问题,但有一些关于您的代码的评论。
看来你修改了一个现有的程序,快速添加了一些初步指令输出2和3,但是你没有按照这个调整筛内存的起始地址。在您当前的程序中,地址 31 指向带有 的行(邮箱)BRA WRITELOOP
,这不是您的目的。动态代码 at 第一次READINS
执行时,该位置有指令LDA INPUT
as INPUT
,对应于地址 33。
这也是程序不输出 5 作为素数的原因。除了您已经使用的数据之外,该程序应该真正指向为它的筛子释放内存。为了节省空间,您可以让筛子地址从标签开始ONE
,因为筛子的前两个条目永远不会被访问。
我认为使用标签和助记符而不是硬编码的操作码和地址也更好,因此避免使用 331 和 531 之类的东西,它们非常神秘,并且(如图所示)在修改程序时容易出错。
此外,您应该明确列出DAT
您的程序将使用的条目。
这是一个更正的版本,显然对输入仍有限制:67 是您可以在不破坏代码的情况下输入的最大值。
#input: 67
INP
STA INPUT
LOOP LDA A \\ first loop
ADD ONE
STA A
SUB INPUT
BRP END
LDA A
ADD LDINS
STA READINS
READINS DAT
BRZ PRIME
BRA LOOP
PRIME LDA A
OUT
STA B
WRITELOOP LDA B \\ second loop
SUB INPUT
BRP LOOP
LDA B
ADD STINS
STA WRINS
LDA A
WRINS DAT
LDA B
ADD A
STA B
BRA WRITELOOP
END HLT
INPUT DAT
LDINS LDA ONE
STINS STA ONE
A DAT 1
ONE DAT 1 // also the start of the sieve
B DAT
<script src="https://cdn.jsdelivr.net/gh/trincot/lmc@v0.76/lmc.js"></script>