views:

421

answers:

6

Since many of the Project Euler problems require you to do a divisibility check for quite a number of times, I've been trying to figure out the fastest way to perform this task in ZX81 BASIC.

So far I've compared (N/D) to INT(N/D) to check, whether N is dividable by D or not.
I have been thinking about doing the test in Z80 machine code, I haven't yet figured out how to use the variables in the BASIC in the machine code.

How can it be achieved?

A: 

You should place the values in some pre-known memory locations, first. Then use the same locations from within Z80 assembler. There is no parameter passing between the two.

This is based on what I (still) remember of ZX Spectrum 48. Good luck, but you might consider upgrading your hw. ;/

akauppi
Now, what's the challenge in throwing more hardware to a problem? :-D
DJ Pirtu
+3  A: 

Your existing solution may be good enough. Only replace it with something faster if you find it to be a bottleneck in profiling.

(Said with a straight face, of course.)

And anyway, on the ZX81 you can just switch to FAST mode.

Daniel Earwicker
I'm quite aware of the FAST mode. Unfortunately, when I tried my algorithm of finding the 10001st prime, it took 10 hours even with the FAST mode on.
DJ Pirtu
Okay, just get a hundred ZX81s and connect them together with RS-232 cables. Hey presto - a thread pool!
Daniel Earwicker
@Earwicker: Don't know about the answer, but I just have to upvote this for the sheer hilarity of that comment :-)
DJ Pirtu
A: 

The problem with Z80 machine code is that it has no floating point ops (and no integer divide or multiply, for that matter). Implementing your own FP library in Z80 assembler is not trivial. Of course, you can use the built-in BASIC routines, but then you may as well just stick with BASIC.

anon
Well, one good thing about Project Euler problems is, that you don't realy need float points. Integral calculations will do just fine. The problem comes from finding out, if a number is devidable into integrals.
DJ Pirtu
But your N/D = INT(N/D) does use FP, no?
anon
That it does, which is why I suspect that there might be a way to do the test more effeciently, using something that does not use float points.
DJ Pirtu
+2  A: 

Don't know if RANDOMIZE USR is available in ZX81 but I think it can be used to call routines in assembly. To pass arguments you might need to use POKE to set some fixed memory locations before executing RANDOMIZE USR.

I remember to find a list of routines implemented in the ROM to support the ZX Basic. I'm sure there are a few to perform floating operation.

An alternative to floating point is to use fixed point math. It's a lot faster in these kind of situations where there is no math coprocessor.

You also might find more information in Sinclair User issues. They published some articles related to programming in the ZX Spectrum

jassuncao
A: 

Doesn't ZX81 BASIC have a MOD function?

Eric
As far as I know, no.You're free to prove me wrong, but the ZX81 BASIC Programming guide (http://web.ukonline.co.uk/sinclair.zx81/) didn't mention anything like it.
DJ Pirtu
+3  A: 

You can do this very fast in machine code by subtracting repeatedly. Basically you have a procedure like:

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

The 8 bit version would be something like:

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

Now, you can call from basic using USR. What USR returns is whatever's in the BC register pair, so you would probably want to do something like:

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

This is an introduction I wrote to Z80 which should help you figure this out. This will explain the flags if you're not familiar with them. There's a load more links to good Z80 stuff from the main site although it is Spectrum rather than ZX81 focused.

A 16 bit version would be quite similar but using register pair operations. If you need to go beyond 16 bits it would get a bit more convoluted.

How you load this is up to you - but the traditional method is using DATA statements and POKEs. You may prefer to have an assembler figure out the machine code for you though!

cyborg
As a follow up I should probably add that you can do long division if this is too slow but it's a bit more fiddly.
cyborg