Быстрая проверка делимости в ZX81 BASIC
Вопрос
Поскольку многие из проблем Project Euler требуют от вас проверки делимости довольно много раз, я пытался найти самый быстрый способ выполнить эту задачу в ZX81 BASIC.
До сих пор я сравнивал (N / D)
с INT (N / D)
, чтобы проверить, можно ли делить N
на D
или нет.
Я думал о проведении теста в машинном коде Z80 , пока не знаю выяснил, как использовать переменные в бейсике в машинном коде.
Как этого достичь?
Решение
Не знаю, доступен ли RANDOMIZE USR в ZX81, но я думаю, что его можно использовать для вызова подпрограмм в сборке. Для передачи аргументов вам может понадобиться использовать POKE, чтобы установить несколько фиксированных областей памяти перед выполнением RANDOMIZE USR.
Я не забываю найти список подпрограмм, реализованных в ПЗУ для поддержки ZX Basic. Я уверен, что есть несколько, чтобы выполнить плавающую операцию.
Альтернативой плавающей запятой является использование математики с фиксированной запятой. Это намного быстрее в подобных ситуациях, когда нет математического сопроцессора.
Вы также можете найти больше информации в вопросах пользователя Sinclair. Они опубликовали несколько статей, связанных с программированием в ZX Spectrum
Другие советы
Вы можете сделать это очень быстро в машинном коде, вычитая несколько раз. По сути, у вас есть такая процедура:
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, должно помочь вам понять это. Это будет объясните флаги, если вы не знакомы с ними. На основном сайте есть много ссылок на хорошие материалы по Z80, хотя речь идет о спектруме, а не о ZX81.
16-битная версия была бы очень похожа, но с использованием операций пары регистров. Если вам нужно выйти за пределы 16 бит, это будет немного более запутанным.
Как вы загружаете это, зависит от вас - но традиционный метод использует операторы DATA и POKE. Вы можете предпочесть, чтобы ассемблер выяснил машинный код для вас!
Ваше существующее решение может быть достаточно хорошим. Заменяйте его на что-то более быстрое, если вы обнаружите, что это является узким местом в профилировании.
(Сказано с невозмутимым лицом, конечно.)
И в любом случае, на ZX81 вы можете просто переключиться в режим FAST.
Сначала вы должны поместить значения в некоторые заранее известные области памяти. Затем используйте те же места в ассемблере Z80. Между ними нет передачи параметров.
Это основано на том, что я (до сих пор) помню о ZX Spectrum 48. Удачи, но вы можете рассмотреть вопрос об обновлении вашего hw. ; / Р>
Проблема с машинным кодом Z80 состоит в том, что у него нет операций с плавающей запятой (и, в этом отношении, нет целочисленного деления или умножения). Реализация вашей собственной библиотеки FP в ассемблере Z80 не тривиальна. Конечно, вы можете использовать встроенные подпрограммы BASIC, но тогда вы можете просто придерживаться BASIC.