Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve fixed-point documentation #1455

Merged
merged 10 commits into from
Aug 8, 2024
111 changes: 73 additions & 38 deletions man/rgbasm.5
Original file line number Diff line number Diff line change
Expand Up @@ -369,63 +369,93 @@ equals $roman clz ( n )$.
delim off
.EN
.Ss Fixed-point expressions
Fixed-point numbers are basically normal (32-bit) integers, which count fractions instead of whole numbers.
They offer better precision than integers but limit the range of values.
By default, the upper 16 bits are used for the integer part and the lower 16 bits are used for the fraction (65536ths).
The default number of fractional bits can be changed with the
Fixed-point numbers are technically just integers, but conceptually they have a decimal point at a fixed location (hence the name).
This gives them increased precision, at the cost of a smaller range, while remaining far cheaper to manipulate than floating-point numbers (which
.Nm
does not support).
.Pp
The default precision of all fixed-point numbers is 16 bits, meaning the lower 16 bits are used for the fractional part; so they count in 65536ths of 1.0.
This precision can be changed with the
.Fl Q
command-line option.
You can also specify a precise fixed-point value by appending a
command-line option, and/or by
.Ic OPT Q
.Pq see Sx Changing options while assembling .
An individual fixed-point literal can specify its own precision, overriding the current default, by appending a
.Dq q
to it followed by the number of fractional bits, such as
.Ql 12.34q8 .
followed by the number of fractional bits: for example,
.Ql 1234.5q8
is equal to $0004d2_80
.EQ
delim $$
.EN
($= 1234.5 * 2 sup 8$).
ISSOtm marked this conversation as resolved.
Show resolved Hide resolved
.Pp
Since fixed-point values are still just integers, you can use them in normal integer expressions.
Some integer operators like
.Sq +
and
.Sq -
don't care whether the operands are integers or fixed-point.
You can easily truncate a fixed-point number into an integer by shifting it right by the number of fractional bits.
It follows that you can convert an integer to a fixed-point number by shifting it left that same amount.
.Pp
Note that the current number of fractional bits can be computed as
.Ic TZCOUNT Ns Pq 1.0 .
.Pp
The following functions are designed to operate with fixed-point numbers:
.EQ
delim $$
.EN
.Bl -column -offset indent "ATAN2(y, x)"
.It Sy Name Ta Sy Operation
.It Fn DIV x y Ta Fixed-point division $( x \[di] y ) \[mu] ( 2 ^ precision )$
.It Fn MUL x y Ta Fixed-point multiplication $( x \[mu] y ) \[di] ( 2 ^ precision )$
.It Fn FMOD x y Ta Fixed-point modulo $( x % y ) \[di] ( 2 ^ precision )$
.It Fn POW x y Ta $x$ to the $y$ power
.It Fn LOG x y Ta Logarithm of $x$ to the base $y$
.It Fn DIV x y Ta Fixed-point division
.It Fn MUL x y Ta Fixed-point multiplication
.It Fn FMOD x y Ta Fixed-point modulo
.It Fn POW x y Ta $x sup y$
ISSOtm marked this conversation as resolved.
Show resolved Hide resolved
.It Fn LOG x y Ta $log sub y ( x )$ (such that
.Ic LOG Ns ( Ic POW Ns ( x , y ) , y ) == x)
ISSOtm marked this conversation as resolved.
Show resolved Hide resolved
.It Fn ROUND x Ta Round $x$ to the nearest integer
.It Fn CEIL x Ta Round $x$ up to an integer
.It Fn FLOOR x Ta Round $x$ down to an integer
.It Fn CEIL x Ta Round $x$ up to the nearest integer
.It Fn FLOOR x Ta Round $x$ down to the nearest integer
.It Fn SIN x Ta Sine of $x$
.It Fn COS x Ta Cosine of $x$
.It Fn TAN x Ta Tangent of $x$
.It Fn ASIN x Ta Inverse sine of $x$
.It Fn ACOS x Ta Inverse cosine of $x$
.It Fn ATAN x Ta Inverse tangent of $x$
.It Fn ASIN x Ta Inverse sine of $x$ (such that
.Ic ASIN Ns ( Ic SIN Ns ( x ) ) == x)
.It Fn ACOS x Ta Inverse cosine of $x$ (such that
.Ic ACOS Ns ( Ic COS Ns ( x ) ) == x)
.It Fn ATAN x Ta Inverse tangent of $x$ (such that
.Ic ATAN Ns ( Ic TAN Ns ( x ) ) == x)
ISSOtm marked this conversation as resolved.
Show resolved Hide resolved
.It Fn ATAN2 y x Ta Angle between $( x , y )$ and $( 1 , 0 )$
.El
.EQ
delim off
.EN
.Pp
All of these fixed-point functions can take an optional final argument, which is the precision to use.
There are no functions for fixed-point addition and subtraction, because the
.Sq +
and
.Sq -
operators can add and subtract pairs of fixed-point operands.
.Bd -ragged -offset indent
Note that some operators or functions are meaningful when combining integers and fixed-point values.
For example,
.Ql 2.0 * 3
is equivalent to
.Ql MUL(2.0, 3.0) ,
and
.Ql 6.0 / 2
is equivalent to
.Ql DIV(6.0, 2.0) .
Be careful and think about what the operations mean when doing this sort of thing.
.Ed
.Pp
All of these fixed-point functions can take an optional final argument, which is the precision to use for that one operation.
For example,
.Ql MUL(6.0q8, 7.0q8, 8)
will evaluate to
.Ql 42.0q8
no matter what value is set as the current
.Cm Q
option.
.Nm
.Em does not check precisions for consistency ,
so nonsensical input like
.Ql MUL(4.2q8, 6.9q12, 16)
will produce a nonsensical (but technically correct) result:
.Dq garbage in, garbage out .
.Pp
The
.Ic FMOD
Expand All @@ -439,21 +469,26 @@ this is the opposite of how the integer modulo operator
.Sq %
works!
.Pp
The trigonometry functions (
.Ic SIN ,
.Ic COS ,
.Ic TAN ,
etc) are defined in terms of a circle divided into 1.0 "turns" (equal to 2pi radians or 360 degrees).
The trigonometry functions
.Pq Ic SIN , Ic COS , Ic TAN , No etc
are defined in terms of a circle divided into 1.0
.Dq turns
.EQ
delim $$
.EN
(equal to $2 pi$ radians, or 360 degrees).
.EQ
delim off
.EN
.Pp
These functions are useful for automatic generation of various tables.
For example:
.Bd -literal -offset indent
; Generate a table of sine values from sin(0.0) to sin(1.0), with
; amplitude scaled from [-1.0, 1.0] to [0.0, 128.0]
DEF turns = 0.0
REPT 256
db MUL(64.0, SIN(turns) + 1.0) >> 16
DEF turns += 1.0 / 256
; Generate a table of 128 sine values
; from sin(0.0) to sin(0.5) excluded,
; with amplitude scaled from [-1.0, 1.0] to [0.0, 128.0].
FOR angle, 0.0, 0.5, 0.5 / 128
db MUL(SIN(angle) + 1.0, 128.0 / 2) >> 16
ENDR
.Ed
.Ss String expressions
Expand Down
Loading