ZXSimulator

Anything QL Software or Programming Related.
User avatar
NormanDunbar
Forum Moderator
Posts: 2456
Joined: Tue Dec 14, 2010 9:04 am
Location: Buckie, Scotland
Contact:

Re: ZXSimulator

Post by NormanDunbar »

The above example was multiplication, not addition.
Yes indeed, but that's what I was typing about, multiplication not addition.

My point was, if you multiply two numbers with two fixed point decimal places, your answer will have four (2+2) decimals.

However, as you pointed out, you are using 16 bits, so my query doesn't apply given the ease with which things overflow.

Cheers,
Norm.


Why do they put lightning conductors on churches?
Author of Arduino Software Internals
Author of Arduino Interrupts

No longer on Twitter, find me on https://mastodon.scot/@NormanDunbar.
User avatar
bwinkel67
QL Wafer Drive
Posts: 1511
Joined: Thu Oct 03, 2019 2:09 am

Re: ZXSimulator

Post by bwinkel67 »

NormanDunbar wrote: Thu Jun 20, 2024 10:06 pm My point was, if you multiply two numbers with two fixed point decimal places, your answer will have four (2+2) decimals.

Ah, I see what you are saying. Yes and the accounting method of representing decimal numbers as the 1's and 10's place also captures that:

In decimal we have:

1.25 x 2.25 = 2.8125

In the "accounting" method we have:

125 x 225 = 28125

So it gives the expected identically results -- Math works :-). Unfortunately I need to divide by 100 to get it back to 2-point fixed decimal (otherwise my result will be interpreted and displayed as 281.25) so I get:

125 x 225 = 28125 / 100 = 2812 which represents 2.81


So one curiosity, with fixed decimal, should I do rounding or leave it be? Here's an example...

Should this get:

248 x 135 = 33480/100 = 334 which represents 3.34

Or should I do this instead:

248 x 135 = (33480+50)/100 = 33530/100 = 335 which represents 3.35


Note: the ZX81 does that for indexing and addressing, i.e. GOTO and GOSUB, so GOTO 10.4 jumps to 10 and GOTO 10.5 jumps to 11. But the ZX81 does use floating point and I suppose it rounds at the end but that's at like the 8th or 9th decimal place, not at the 2nd one.


User avatar
NormanDunbar
Forum Moderator
Posts: 2456
Joined: Tue Dec 14, 2010 9:04 am
Location: Buckie, Scotland
Contact:

Re: ZXSimulator

Post by NormanDunbar »

Ah rounding! A similar nightmare to Unicode! ;)

If the ZX-81 rounds down for < x.5 and up for >= x.5, the I would follow that.

You don't want to get into banker's rounding where x.5 rounds to the nearest even number!

HTH

Cheers,
Norm.


Why do they put lightning conductors on churches?
Author of Arduino Software Internals
Author of Arduino Interrupts

No longer on Twitter, find me on https://mastodon.scot/@NormanDunbar.
User avatar
bwinkel67
QL Wafer Drive
Posts: 1511
Joined: Thu Oct 03, 2019 2:09 am

Re: ZXSimulator

Post by bwinkel67 »

NormanDunbar wrote: Fri Jun 21, 2024 7:48 pm If the ZX-81 rounds down for < x.5 and up for >= x.5, the I would follow that.
Yes, for numbers that must be integers (i.e. line numbers) I do round down for < x.5 and up for >= x.5. My question was though what do I do for fixed-decimal (2 place) numbers. The ZX81 likely does use the same formula, but at higher precision, i.e. it rounds down for < x.000000005 and up for >= x.000000005 so that if your number is 1.000000007 it becomes 1.00000001. However, that's a pretty small change being so far down precision at the 8th decimal places. If I round at < x.005 and >= x.005, that's only 3 decimal places...should I still do it?


User avatar
bwinkel67
QL Wafer Drive
Posts: 1511
Joined: Thu Oct 03, 2019 2:09 am

Re: ZXSimulator

Post by bwinkel67 »

Here is my bug-for-bug compatible 32-bit fixed-point decimal versions. I say bug-for-bug because my 16-bit integer version has a few bugs I need to fix. Download it and give it a try...see if it breaks on standard ZX81 BASIC (you can take .p files, convert them to BASIC and read that into ZXSimulator). Note that it does basic arithmetic, but no functions like COS, SIN, etc, have yet been implemented...that'll be the final step.

zx.zip
(38.14 KiB) Downloaded 114 times

First, I really enjoyed working on this. It made me remember how cool the QL was for me back in the 90's when all I had was it and a C compiler (Digital 'C' SE). Eventually I got a floppy and, along with a bit faster (and somewhat more reliable) media, I also got a subset of the TK2 instructions without losing my ROM port (i.e. I got ICE and a sub-TK2 all in ROM with no memory loss...those where the days).

Converting to 32-bit was a bit of a pain, mainly because I didn't want to wholesale replace every "int" with a "long" value. The issue with Digital 'C' SE is that it can do certain conversions but fails on others and it took me two solid days (until my wife had to get me as I was out in the tent coding past midnight each day) to figure it out. Luckily, good old prints in the code (which itself was a bit of a pain since I had to use the ZXprintf routine) helped.

So the compiler allows this:

Code: Select all

int i;
long j;

i = j;
j = i;
...but then it struggles with any other cross type stuff. You cannot send an "int" into a function expecting a "long"...that one took most of my effort to figure out. The manual says that you must put an "L" after any literal, though that only seems to be the case in assignment since, if you leave it out within an "if" statement, it still works.

I used QLAY to do my work, and got tired of typing so I wrote a some helper scripts (SuperBASIC).

This was one of four that would recompile a module and link it, etc -- I had one each for cmd_c, aux_c, expr_c, and graph_c (oh, and for whatever reason, on QLAY, the compiler hangs if I use WIN_ as devices, so I use MDV_ instead...it's a QLAY thing, not the compiler's fault):

Code: Select all

10 DELETE mdv2_zx: DELETE mdv2_expr_c: COPY win1_expr_c TO mdv2_expr_c: EXEC_W mdv3_cc;"expr_c -m -p": DELETE mdv2_expr_c: EXEC_W mdv3_cg;"zx cmd aux expr graph -nc": EXEC mdv2_zx
..and I wrote a distro script:

Code: Select all

10 DELETE win1_zx: COPY mdv2_zx TO win1_zx: DELETE mdv2_zx: DELETE mdv2_zx_zip: DELETE mdv2_src_zip
20 EXEC_W win7_zip;"src win1_cmd_h win1_cmd_c win1_aux_c win1_expr_c win1_graph_c"
30 DELETE win1_src_zip: COPY mdv2_src_zip TO win1_src_zip: DELETE mdv2_src_zip
40 EXEC_W win7_zip;"zx win1_zx win1_ball_bas win1_banner_bas win1_battleship_bas win1_elite_bas win1_src_zip"

[Edit: to see the new features, just work with fractions. It's only 2 decimal precision, but it does work. I haven't done the rounding yet that I thought I might do so all values just get truncated after the 2nd spot.]


User avatar
NormanDunbar
Forum Moderator
Posts: 2456
Joined: Tue Dec 14, 2010 9:04 am
Location: Buckie, Scotland
Contact:

Re: ZXSimulator

Post by NormanDunbar »

bwinkel67 wrote: If I round at < x.005 and >= x.005, that's only 3 decimal places...should I still do it?
If the '81 does it that way, then yes, I would try to copy that method as far as possible.

I have this video to watch in my You Tube list, it might be useful. https://youtu.be/i1phJl-0v54?si=ig2XusbnpfzMa-rE

Sorry, been in Scotland visiting my dad in his care home. The doctors have him on end of life care now. 😟


Cheers,
Norm.


Why do they put lightning conductors on churches?
Author of Arduino Software Internals
Author of Arduino Interrupts

No longer on Twitter, find me on https://mastodon.scot/@NormanDunbar.
User avatar
bwinkel67
QL Wafer Drive
Posts: 1511
Joined: Thu Oct 03, 2019 2:09 am

Re: ZXSimulator

Post by bwinkel67 »

NormanDunbar wrote: Wed Jun 26, 2024 8:46 am I have this video to watch in my You Tube list, it might be useful. https://youtu.be/i1phJl-0v54?si=ig2XusbnpfzMa-rE
That's a good video. I'm basically splitting my number up into 1/24/7, where 1 bit is for the sign, 24 bits is for my whole number part, and 7 bits for the fraction part. It's not quite that since 7 bits gives you 128 divisions on the number line, and I'm basing mine on decimal, so I have only 100 divisions (0 to 99). However, that also gives me a slightly larger number than 24 bits does, i.e. 24 bits usually gives a max of 16,777,216 and my max is 21,474,836 (basically 2^31 / 100).
NormanDunbar wrote: Wed Jun 26, 2024 8:46 am Sorry, been in Scotland visiting my dad in his care home. The doctors have him on end of life care now. 😟
Oh, I'm really sorry to hear that. My thoughts are with your family.


User avatar
bwinkel67
QL Wafer Drive
Posts: 1511
Joined: Thu Oct 03, 2019 2:09 am

Re: ZXSimulator

Post by bwinkel67 »

Here is an updated version of the base-10 fixed decimal version.

zx.zip
(38.08 KiB) Downloaded 118 times

It runs about 8% faster than the last version and about 5% faster than the integer-based one. I removed unneeded code to improve its speed. The original BASIC interpreter was designed with ZX81 BASIC and QL SuperBASIC features. So one SuperBASIC feature it had was that a string could act like a number, and vice versa (not SuperBASIC-like). So you could do things like "2" * 3 and get 6 as a result, or do something like "2" + 3 and get string 23. This required constant duplication of numeric values to string values and string values to numeric values as it ran up and down the expression tree. It may have ended up doing it 4 or 5 times (lots of atoi, itoa, and strcpy in there).

Now, I presently still create a string for a numeric variable and have an int for a string variable, but I set the string to empty or the int to zero depending type of variable. So, I took out all that repetitive code that freed and re-allocated strings, etc. The other interesting feature is that I fixed the random number generator...I'll do a separate post on that...
Last edited by bwinkel67 on Wed Jul 03, 2024 11:24 am, edited 2 times in total.


User avatar
bwinkel67
QL Wafer Drive
Posts: 1511
Joined: Thu Oct 03, 2019 2:09 am

Re: ZXSimulator

Post by bwinkel67 »

...and here is my first typed-in program requiring non-integer math from the web. It's simple but it worked right away.

So first, the program I found on the web:
degree-source.png

Next, after typing it in, here is my version:
degree-list.png

...and finally, running it gives the correct asnwer:
degree-run.png
Last edited by bwinkel67 on Sat Jul 06, 2024 6:51 am, edited 1 time in total.


User avatar
bwinkel67
QL Wafer Drive
Posts: 1511
Joined: Thu Oct 03, 2019 2:09 am

Re: ZXSimulator

Post by bwinkel67 »

Implementing a working random number generator (RNG) with only 2-point precision was interesting. I first tried to implement the RNG that the ZX81 used as stated in Wikipedia on Lehmer RNGs:

seed = (75 * seed) / 65537

That didn't quite work, as it showed some patterns in its scatter plot, though the histogram showed it being evenly distributed:

zx81_lehmer.png

Then I realized the ZX81 BASIC book actually gives the formula they used, which is slightly different from the Wikipedia article:

seed = (75 * (seed + 1) - 1) / 65536

However, that also didn't work out as the scatter plot still showed the same issues, and the histogram is a little different (maybe a little less even as the two values are 656 and 648 as opposed to 656 and 655):

zx81_book.png

So, I had to look for a different RNG and found this one online (I don't know what it's called):

seed = (31421 * seed + 6927) % 65536

This one works, and passes all the markers...the plots below show it in stages from about 1100 values, to 3300 values, to fully covered:

ZXSim_rand.png

I haven't tested the RNG that the ZX81 (and presumably the Spectrum) uses with full floating point precision but I suspect it does just fine. It's this 2-point precision that seems to trip it up and I don't really understand why? Does that mean we are seeing some flaws in it?


[Edit: Here are is the scatter plot and histogram BASIC programs]

Code: Select all

10 LET X=RND
20 FOR I=1 TO 65536
30 LET Y=RND
40 PLOT INT (X*64),INT (Y*44)
50 LET X=Y
60 NEXT I

Code: Select all

10 DIM A(100)
20 FOR I=1 TO 65536
30 LET J=INT (RND*100)+1
40 LET A(J)=A(J)+1
50 NEXT I
60 FOR I=1 TO 100
70 PRINT A(I);", ";
80 NEXT I


Post Reply