由于许多 Project Euler 问题需要您多次进行整除性检查,因此我一直试图找出在ZX81 BASIC 中执行此任务的最快方法。
到目前为止,我已经比较(N/D)
了INT(N/D)
是否N
可以除以D
。
一直在想用Z80机器码做测试,还没想清楚如何在机器码中使用BASIC中的变量。
如何实现?
您可以通过重复减法在机器代码中非常快速地做到这一点。基本上你有一个像这样的程序:
set accumulator to N
subtract D
if carry flag is set then it is not divisible
if zero flag is set then it is divisible
otherwise repeat subtraction until one of the above occurs
8 位版本将类似于:
DIVISIBLE_TEST:
LD B,10
LD A,100
DIVISIBLE_TEST_LOOP:
SUB B
JR C, $END_DIVISIBLE_TEST
JR Z, $END_DIVISIBLE_TEST
JR $DIVISIBLE_TEST_LOOP
END_DIVISIBLE_TEST:
LD B,A
LD C,0
RET
现在,您可以使用 USR 从基本呼叫。USR 返回的是 BC 寄存器对中的任何内容,因此您可能想要执行以下操作:
REM poke the memory addresses with the operands to load the registers
POKE X+1, D
POKE X+3, N
LET r = USR X
IF r = 0 THEN GOTO isdivisible
IF r <> 0 THEN GOTO isnotdivisible
这是我写给 Z80 的介绍,应该可以帮助您解决这个问题。如果您不熟悉这些标志,这将解释它们。尽管它是 Spectrum 而不是 ZX81 的重点,但主站点上有更多指向 Z80 好东西的链接。
16 位版本将非常相似,但使用寄存器对操作。如果您需要超过 16 位,它会变得更加复杂。
你如何加载它取决于你——但传统的方法是使用 DATA 语句和 POKE。不过,您可能更喜欢让汇编程序为您找出机器代码!
您现有的解决方案可能已经足够好了。如果您发现它是分析中的瓶颈,请仅将其替换为更快的东西。
(当然是板着脸说。)
无论如何,在 ZX81 上,您只需切换到 FAST 模式即可。
不知道 RANDOMIZE USR 是否在 ZX81 中可用,但我认为它可以用来调用汇编中的例程。要传递参数,您可能需要在执行 RANDOMIZE USR 之前使用 POKE 设置一些固定的内存位置。
我记得在 ROM 中找到了一个支持 ZX Basic 的例程列表。我敢肯定有几个可以执行浮动操作。
浮点的替代方法是使用定点数学。在这种没有数学协处理器的情况下,它要快得多。
您还可以在 Sinclair 用户问题中找到更多信息。他们在 ZX Spectrum 上发表了一些与编程相关的文章
您应该首先将这些值放在一些预先知道的内存位置。然后使用 Z80 汇编器中的相同位置。两者之间没有参数传递。
这是基于我(仍然)记得的 ZX Spectrum 48。祝你好运,但你可能会考虑升级你的硬件。;/
Z80 机器代码的问题在于它没有浮点运算(就此而言,也没有整数除法或乘法)。在 Z80 汇编器中实现您自己的 FP 库并非易事。当然,你可以使用内置的 BASIC 例程,但你也可以坚持使用 BASIC。