rgbds icon indicating copy to clipboard operation
rgbds copied to clipboard

Implement `opt Q` for fixed-point precision

Open Rangi42 opened this issue 3 years ago • 4 comments

Fixes #957

Rangi42 avatar Dec 16 '21 03:12 Rangi42

Should "certain-precision" literals (which would be interpreted with a given precision regardless of the opt f level) use p or q?

I'm leaning toward q, since it matches the "Qm.n" notation; and unlike #956, there's no %p format spec for them to go with. Also this PR uses opt f not opt p because p is already taken for the pad value; but I'd rather not do 12.34f8 since it's confusable with a hex digit.

(Also maybe this should use -q and opt q instead of f?)

Rangi42 avatar Dec 16 '21 03:12 Rangi42

I like the idea of going with q, and in that case, it seems sensible to just use -q for the option too.

aaaaaa123456789 avatar Dec 16 '21 03:12 aaaaaa123456789

Discussion of a problem with this so far: https://discord.com/channels/303217943234215948/661193788802203688/921569990791036928

Rangi42 avatar Jul 03 '22 21:07 Rangi42

I think opt Q is ready to review as-is; 12.34q.8 literals can be their own PR. (Even without them, just having opt Q makes it easier to write a fully Q.8 fixed-point project, for instance.)

Edit: ...huh, at some point I implemented q literals already, with tests for them, and just forgot. :P

Rangi42 avatar Jul 09 '22 17:07 Rangi42

pret will be able to use this when 0.6.0 is out: the sine_table macro can be simplified from this:

MACRO sine_table
; \1 samples of sin(x) from x=0 to x<0.5 units (pi radians)
	DEF x = 0
	rept \1
		dw (sin(x) + (sin(x) & $ff)) >> 8 ; round up
		DEF x += div(0.5, \1) ; a circle has 1.0 units (tau radians)
	endr
ENDM

to this, with rgbasm -Q8 and with a workable for loop since two's-complement underflow is no longer a problem:

MACRO sine_table
; \1 samples of sin(x) from x=0 to x<0.5 units (pi radians)
	for x, \1
		dw sin(x * div(0.5, \1)) ; a circle has 1.0 units (tau radians)
	endr
ENDM

Rangi42 avatar Aug 29 '22 02:08 Rangi42

My polishedcrystal project also has an opportunity to use opt Q. Most fixed-point math in it is best done with -Q8, just like pret, but one line is not: ld de, div(1.0, 25.4) (1 inch / 25.4 mm = 0.03937 in/mm) expects ld de, $0A14, but with 8.8 fixed-point that would be ld de, $000A. The solution:

pusho
opt Q16
	ld de, div(1.0, 25.4) ; 1 in / 25.4 mm = 0.03937 in/mm
popo

(This can't just use q literals, as ld de, div(1.0q16, 25.4q16) would still be doing the division in the default -Q8 context.)

Rangi42 avatar Aug 30 '22 04:08 Rangi42

Looks good to me, although the issue with insufficient literal precision remains to be fixed.

This is referring to how fixed-point literals are not currently lexed with enough precision to specify all 65,536 possible values, at least not for extreme values of Q. For instance, at -Q31 (Q1.31 fixed-point), 0.0000000009 is $0000 but 0.0000000010 is $0002, with no literal for $0001. IMO not a blocker for this feature.

Rangi42 avatar Aug 30 '22 14:08 Rangi42

Looks good to me, although the issue with insufficient literal precision remains to be fixed.

This is referring to how fixed-point literals are not currently lexed with enough precision to specify all 65,536 possible values, at least not for extreme values of Q. For instance, at -Q31 (Q1.31 fixed-point), 0.0000000009 is $0000 but 0.0000000010 is $0002, with no literal for $0001. IMO not a blocker for this feature.

Agreed, hence my approving review. (By the way, since only 9 decimal places are lexed, any precision >= 9 can have rounding errors. Of course, 31 maximises them.)

aaaaaa123456789 avatar Aug 30 '22 14:08 aaaaaa123456789