8.8 Fixed Point arithmetic

The place for codemasters or beginners to talk about programming any language for the Spectrum.
Post Reply
presh
Manic Miner
Posts: 237
Joined: Tue Feb 25, 2020 8:52 pm
Location: York, UK

8.8 Fixed Point arithmetic

Post by presh »

Looking for some working Z80 code for multiplying and dividing *signed* 8.8 Fixed Point numbers.

The example mulfixed8_8 I found at Z80 Heaven seems to output D.E * D.E, rather than H.L * D.E as advertised. (The mul16 subroutine seems to work fine)

And the method I found at cemetech is unsigned only.

(I haven't tried the 8.8 division routine yet!)

Anyone got some go-to routines for these which they have verified working?

:?
presh
Manic Miner
Posts: 237
Joined: Tue Feb 25, 2020 8:52 pm
Location: York, UK

Re: 8.8 Fixed Point arithmetic

Post by presh »

Perhaps I have misinterpreted some of the code. This part of mulfixed8_8 wouldn't compile in Pasmo, as the label _: is repeated, e.g.

Code: Select all

; Now make sure the inputs are positive
  xor d     ;A now has the value of H, since I XORed it with D twice (cancelling)
  jp p,+_  ;if Positive, don't negate
  xor a
  sub l
  ld l,a
  sbc a,a
  sub h
  ld h,a
_:
  bit 7,d
  jr z,+_
  xor a
  sub e
  ld e,a
  sbc a,a
  sub d
  ld d,a
_:
Which gives:

Code: Select all

ERROR on line 26 of file mulfixed8_8.asm
ERROR: Invalid definition, previously defined as EQU or label
So I've changed the labels as follows:

Code: Select all

; Now make sure the inputs are positive
  xor d     ;A now has the value of H, since I XORed it with D twice (cancelling)
  jp p,_1   ;if Positive, don't negate
  xor a
  sub l
  ld l,a
  sbc a,a
  sub h
  ld h,a
_1:
  bit 7,d
  jp z,_2
  xor a
  sub e
  ld e,a
  sbc a,a
  sub d
  ld d,a[color=#FF0000]
_2:
But perhaps I have misunderstood what jp [cond ,] +[label] means (I've not seen a + used before a label) and fudged the logic as a result?
catmeows
Manic Miner
Posts: 718
Joined: Tue May 28, 2019 12:02 pm
Location: Prague

Re: 8.8 Fixed Point arithmetic

Post by catmeows »

Jump label looks fine. Why you think the multiplication routine doesn't work?
Proud owner of Didaktik M
User avatar
Joefish
Rick Dangerous
Posts: 2060
Joined: Tue Nov 14, 2017 10:26 am

Re: 8.8 Fixed Point arithmetic

Post by Joefish »

For some 3D stuff I was looking for some 16.8 fixed point maths routines, to reproduce some stuff I did on an ST using 16.16 fixed point with its 32-bit registers. (It was very easy to swap or copy out the 16-bit halves whenever you needed a rounded-off integer). But for the Speccy it meant I'd have to reverse-engineer the 32-bit multiplies and divides I could find and reduce the number of bits involved. No easy task with highly optimised code.

Although I reasoned that the code might run faster if I worked backwards through each step of the calculations, worked out how many bits I needed at each step, and used different sized multiplies / divides as appropriate. It would just take a lot longer to write!
presh
Manic Miner
Posts: 237
Joined: Tue Feb 25, 2020 8:52 pm
Location: York, UK

Re: 8.8 Fixed Point arithmetic

Post by presh »

catmeows wrote: Mon Mar 08, 2021 11:18 am Why you think the multiplication routine doesn't work?
I made a super-simple test (4 x 1.5 = 6)

Called with PRINT USR so it will display the value in BC when we RET (though this will be 256x the actual answer as it discards the fixed point, essentially shifting it left 8 times)

Code: Select all

  ; HL = 4.0
  LD H, 4
  LD L, 0
  
  ; DE = 1.5
  LD D, 1
  LD E, 128
  
  ; H.L = H.L * D.E
  CALL mulfixed8_8
  
  ; RTB (should be 4*1.5*256 = 1536)
  ; instead it's 1.5*1.5*256 = 576!!
  LD B, H
  LD C, L
  ; LD B, 0
  ; LD C, H
  RET 
Changing HL makes no difference.
Result is always D.E * D.E
catmeows
Manic Miner
Posts: 718
Joined: Tue May 28, 2019 12:02 pm
Location: Prague

Re: 8.8 Fixed Point arithmetic

Post by catmeows »

I see the bug. The mul16 computes BC*DE, but the fixed 8.8 pass HL and BC (and BC is copied from DE).
Proud owner of Didaktik M
presh
Manic Miner
Posts: 237
Joined: Tue Feb 25, 2020 8:52 pm
Location: York, UK

Re: 8.8 Fixed Point arithmetic

Post by presh »

catmeows wrote: Mon Mar 08, 2021 12:54 pm I see the bug. The mul16 computes BC*DE, but the fixed 8.8 pass HL and BC (and BC is copied from DE).
Ugh, how did I not spot this!!! They even state it in the comments :oops: Thank you [mention]catmeows[/mention]
; Now we need to put HL in BC to use mul16
ld b,d
ld c,e
call mul16
:roll:

I also spotted another typo just below (though this won't make the whole thing fail - just wrong overflow value):
;We should check for overflow. If D>0, we will set HL to 0x7FFF
ld a,d
or a
jp z,_3
ld hl,$FFFF
_3:
presh
Manic Miner
Posts: 237
Joined: Tue Feb 25, 2020 8:52 pm
Location: York, UK

Re: 8.8 Fixed Point arithmetic

Post by presh »

Looks to be working now - thanks again [mention]catmeows[/mention] !

I may be back when I tackle division... :lol:
catmeows
Manic Miner
Posts: 718
Joined: Tue May 28, 2019 12:02 pm
Location: Prague

Re: 8.8 Fixed Point arithmetic

Post by catmeows »

You are welcome.

That is quite interesting page about math, thanks for sharing.
Proud owner of Didaktik M
presh
Manic Miner
Posts: 237
Joined: Tue Feb 25, 2020 8:52 pm
Location: York, UK

Re: 8.8 Fixed Point arithmetic

Post by presh »

Joefish wrote: Mon Mar 08, 2021 11:59 am It was very easy to swap or copy out the 16-bit halves whenever you needed a rounded-off integer
...
I reasoned that the code might run faster if I worked backwards through each step of the calculations, worked out how many bits I needed at each step, and used different sized multiplies / divides as appropriate. It would just take a lot longer to write!
Yeah, this is why I'm using 8.8 even though, say, 4.12 would give greater precision - quick, hassle-free access of the integer part. Nice!

Picking your routines based on expected input/output values sounds like a neat optimisation! Meanwhile, I'm still trying to get the damn thing working at all... maybe I should fix that first :lol:
User avatar
Mpk
Dynamite Dan
Posts: 1008
Joined: Tue Feb 09, 2021 8:10 am

Re: 8.8 Fixed Point arithmetic

Post by Mpk »

I was coming coming here to ask about floats generally, as I need to handle large numbers in my silly project.

Is using the calc stack with 5-character floats and the built-in commands discouraged? Too slow?

Speed is not a concern for me at the moment.

Thanks,
Mpk
User avatar
Einar Saukas
Bugaboo
Posts: 3158
Joined: Wed Nov 15, 2017 2:48 pm

Re: 8.8 Fixed Point arithmetic

Post by Einar Saukas »

Mpk wrote: Mon Mar 08, 2021 5:56 pm Is using the calc stack with 5-character floats and the built-in commands discouraged? Too slow?
Yes, it's much easier but extremely slow.

Mpk wrote: Mon Mar 08, 2021 5:56 pm Speed is not a concern for me at the moment.
In this case, I suggest you go ahead and use the calculator stack. It should be much easier to make your project work this way.

Even if speed becomes a concern later, it should be easier to modify a fully working program to replace these routines, instead of implementing everything the hard way from scratch.
User avatar
Mpk
Dynamite Dan
Posts: 1008
Joined: Tue Feb 09, 2021 8:10 am

Re: 8.8 Fixed Point arithmetic

Post by Mpk »

Alright, thanks!

Slow and steady it is.

Mpk
presh
Manic Miner
Posts: 237
Joined: Tue Feb 25, 2020 8:52 pm
Location: York, UK

Re: 8.8 Fixed Point arithmetic

Post by presh »

[mention]Mpk[/mention] there are also some z80 floating point libraries, which may give you the best of both worlds?

e.g. https://github.com/Zeda/z80float

I haven't tried them as I'm prioritising speed over accuracy (for now, at least)
User avatar
Mpk
Dynamite Dan
Posts: 1008
Joined: Tue Feb 09, 2021 8:10 am

Re: 8.8 Fixed Point arithmetic

Post by Mpk »

Does anyone know of any tutorial / examples for using the calc stack functions?

All I can find is the ROM disassembly pages ( e.g. https://skoolkid.github.io/rom/asm/3014.html) which are thorough, but not very friendly for the neophyte. I can get the multiply working fine, but the addition one just seems to return the top value unaltered. I think I'm not setting the DE/HL pointers correctly.

[mention]presh[/mention] Thanks, I may look at those if I can't get the basic ones working.
ZedaZ80
Drutt
Posts: 8
Joined: Sun Mar 21, 2021 12:06 am

Re: 8.8 Fixed Point arithmetic

Post by ZedaZ80 »

presh wrote: Mon Mar 08, 2021 4:17 pm I also spotted another typo just below (though this won't make the whole thing fail - just wrong overflow value):
;We should check for overflow. If D>0, we will set HL to 0x7FFF
ld a,d
or a
jp z,_3
ld hl,$FFFF
_3:
Thanks, fixed :)

The labels with +_ and -_ come from the spasm assembler popular with Texas Instruments Z80 calculators.

Code: Select all

_: is a temporary label,
+_ refers to the closest following _:, and
-_ refers to the closest preceding _:.
I'm trying to steer away from that niche syntax as I grow older and wiser in the ways of Z80 assembly compilers, but I have a large body of code that was written with spasm in mind.

I've also put these routines up on GitHub here:
mulfixed_88.z80
divfixed_88.z80
sqrtfixed_88.z80
Since they are up on GitHub, feel free to offer optimizations and routines as well as bug reports. I'm fairly busy these days, but I still do Z80 work at least one day a week.

If you do want to venture into using floats, I recommend the 24-bit floats here (these floats are small enough to be passed in registers!). I'm still working on the routines though, so they are apt to change as I find optimizations, but the inputs/outputs will remain the same. Depending on your project, there are 32-bit float routines, as well as 80-bit float routines in that library (you know, in case you need to do some high-precision computing on your Z80 :P).
Post Reply