Changeset View
Standalone View
share/man/man3/qmath.3
- This file was added.
.\" | |||||
.\" Copyright (c) 2018 Netflix, Inc. | |||||
.\" All rights reserved. | |||||
.\" | |||||
.\" Redistribution and use in source and binary forms, with or without | |||||
.\" modification, are permitted provided that the following conditions | |||||
.\" are met: | |||||
.\" 1. Redistributions of source code must retain the above copyright | |||||
.\" notice, this list of conditions, and the following disclaimer, | |||||
.\" without modification, immediately at the beginning of the file. | |||||
.\" 2. The name of the author may not be used to endorse or promote products | |||||
.\" derived from this software without specific prior written permission. | |||||
.\" | |||||
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR | |||||
.\" ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||||
.\" SUCH DAMAGE. | |||||
.\" | |||||
.\" $FreeBSD$ | |||||
.\" | |||||
.Dd July 8, 2018 | |||||
.Dt QMATH 3 | |||||
.Os | |||||
.Sh NAME | |||||
.Nm qmath | |||||
.Nd fixed-point math library based on the | |||||
.Dq Q | |||||
number format | |||||
.Sh SYNOPSIS | |||||
.In sys/qmath.h | |||||
.Ss Functions which create/initialise a Q number. | |||||
.Ft QTYPE | |||||
.Fn Q_INI "QTYPE *q" "ITYPE iv" "int rpshft" | |||||
sef: What is that q doing there? | |||||
Done Inline ActionsI'd swear I've fixed those... Should be ok now. trasz: I'd swear I've fixed those... Should be ok now. | |||||
Not Done Inline ActionsFYI, it was there to say that Q_INI() returned the first operand 'q'. lstewart: FYI, it was there to say that Q_INI() returned the first operand 'q'. | |||||
.Fc | |||||
.Ss Numeric functions which operate on two Q numbers. | |||||
.Ft int | |||||
.Fn Q_QADDQ "QTYPE *a" "QTYPE b" | |||||
.Ft int | |||||
.Fn Q_QDIVQ "QTYPE *a" "QTYPE b" | |||||
.Ft int | |||||
.Fn Q_QMULQ "QTYPE *a" "QTYPE b" | |||||
.Ft int | |||||
.Fn Q_QSUBQ "QTYPE *a" "QTYPE b" | |||||
.Ft int | |||||
Done Inline ActionsTypical convention for short functions like this is: .Ft int .Fn Q_QADDQ "QTYPE *a" "QTYPE b" (Rather than the longer form.) Note also that style(9) puts the * directly adjacent to the following parameter name, without a space in the middle. (Same below, of course.) cem: Typical convention for short functions like this is:
```
.Ft int
.Fn Q_QADDQ "QTYPE *a" "QTYPE… | |||||
.Fn Q_NORMPREC "QTYPE *a" "QTYPE *b" | |||||
.Ft QTYPE | |||||
.Fn Q_QMAXQ "QTYPE a" "QTYPE b" | |||||
.Ft QTYPE | |||||
.Fn Q_QMINQ "QTYPE a" "QTYPE b" | |||||
.Ft int | |||||
.Fn Q_QCLONEQ "QTYPE *l" "QTYPE r" | |||||
.Ft int | |||||
.Fn Q_QCPYVALQ "QTYPE *l" "QTYPE r" | |||||
.Ss Numeric functions which apply integers to a Q number. | |||||
.Ft int | |||||
.Fn Q_QADDI "QTYPE *a" "ITYPE b" | |||||
.Ft int | |||||
.Fn Q_QDIVI "QTYPE *a" "ITYPE b" | |||||
.Ft int | |||||
.Fn Q_QMULI "QTYPE *a" "ITYPE b" | |||||
.Ft int | |||||
.Fn Q_QSUBI "QTYPE *a" "ITYPE b" | |||||
.Ft int | |||||
.Fn Q_QFRACI "QTYPE *q" "ITYPE n" "ITYPE d" | |||||
.Ft int | |||||
.Fn Q_QCPYVALI "QTYPE *q" "ITYPE i" | |||||
.Ss Numeric functions which operate on a single Q number. | |||||
.Ft QTYPE | |||||
.Fn Q_QABS "QTYPE q" | |||||
.Ft double | |||||
.Fn Q_Q2D "QTYPE q" | |||||
.Ft float | |||||
.Fn Q_Q2F "QTYPE q" | |||||
.Ss Comparison and logic functions. | |||||
.Ft bool | |||||
Done Inline ActionsWhat happens if I ${OPERATION} Q numbers with different precision? I think you may want to say, "The fractional component is truncated to fit into the destination, with no rounding." Assuming that's what's actually being done of course :). sef: What happens if I ${OPERATION} Q numbers with different precision?
I think you may want to say… | |||||
Done Inline ActionsWell... one of the implementation details is that the precision of both arguments must match. Still, I like your version, and I've also updated Q_QADDQ.3 to explicitly mention this. trasz: Well... one of the implementation details is that the precision of both arguments must match. | |||||
.Fn Q_SIGNED "NTYPE n" | |||||
.Ft bool | |||||
.Fn Q_LTZ "NTYPE n" | |||||
.Ft bool | |||||
.Fn Q_PRECEQ "QTYPE a" "QTYPE b" | |||||
.Ft bool | |||||
.Fn Q_QLTQ "QTYPE a" "QTYPE b" | |||||
.Ft bool | |||||
.Fn Q_QLEQ "QTYPE a" "QTYPE b" | |||||
.Ft bool | |||||
.Fn Q_QGTQ "QTYPE a" "QTYPE b" | |||||
.Ft bool | |||||
.Fn Q_QGEQ "QTYPE a" "QTYPE b" | |||||
.Ft bool | |||||
.Fn Q_QEQ "QTYPE a" "QTYPE b" | |||||
.Ft bool | |||||
.Fn Q_QNEQ "QTYPE a" "QTYPE b" | |||||
.Ft bool | |||||
.Fn Q_OFLOW "QTYPE q" "ITYPE iv" | |||||
.Ft int | |||||
.Fn Q_RELPREC "QTYPE a" "QTYPE b" | |||||
.Ss Functions which manipulate the control/sign data bits. | |||||
.Ft uint32_t | |||||
.Fn Q_SIGNSHFT "QTYPE q" | |||||
.Ft QTYPE | |||||
.Fn Q_SSIGN "QTYPE q" "bool isneg" | |||||
.Ft ITYPE | |||||
.Fn Q_CRAWMASK "QTYPE q" | |||||
.Ft ITYPE | |||||
.Fn Q_SRAWMASK "QTYPE q" | |||||
.Ft ITYPE | |||||
.Fn Q_GCRAW "QTYPE q" | |||||
.Ft ITYPE | |||||
.Fn Q_GCVAL "QTYPE q" | |||||
.Ft QTYPE | |||||
.Fn Q_SCVAL "QTYPE q" "ITYPE cv" | |||||
.Ss Functions which manipulate the combined integer/fractional data bits. | |||||
.Ft ITYPE | |||||
.Fn Q_IFRAWMASK "QTYPE q" | |||||
.Ft ITYPE | |||||
.Fn Q_IFVALIMASK "QTYPE q" | |||||
.Ft ITYPE | |||||
.Fn Q_IFVALFMASK "QTYPE q" | |||||
.Ft ITYPE | |||||
Done Inline ActionsI can't find Q_INTMAX defined anywhere in the diff. sef: I can't find Q_INTMAX defined anywhere in the diff. | |||||
Done Inline ActionsI suppose it was planned and never actually implemented. Remove for now. trasz: I suppose it was planned and never actually implemented. Remove for now. | |||||
Not Done Inline ActionsOops. FYI Q_INTMAX() did exist but became Q_IMAXVAL() during some refactoring at some point. lstewart: Oops. FYI Q_INTMAX() did exist but became Q_IMAXVAL() during some refactoring at some point. | |||||
.Fn Q_GIFRAW "QTYPE q" | |||||
.Ft ITYPE | |||||
.Fn Q_GIFABSVAL "QTYPE q" | |||||
.Ft ITYPE | |||||
.Fn Q_GIFVAL "QTYPE q" | |||||
.Ft QTYPE | |||||
.Fn Q_SIFVAL "QTYPE q" "ITYPE ifv" | |||||
.Ft QTYPE | |||||
.Fn Q_SIFVALS "QTYPE q" "ITYPE iv" "ITYPE fv" | |||||
.Ss Functions which manipulate the integer data bits. | |||||
.Ft ITYPE | |||||
.Fn Q_IRAWMASK "QTYPE q" | |||||
.Ft ITYPE | |||||
.Fn Q_GIRAW "QTYPE q" | |||||
.Ft ITYPE | |||||
.Fn Q_GIABSVAL "QTYPE q" | |||||
.Ft ITYPE | |||||
.Fn Q_GIVAL "QTYPE q" | |||||
.Ft QTYPE | |||||
.Fn Q_SIVAL "QTYPE q" "ITYPE iv" | |||||
.Ss Functions which manipulate the fractional data bits. | |||||
.Ft ITYPE | |||||
.Fn Q_FRAWMASK "QTYPE q" | |||||
.Ft ITYPE | |||||
.Fn Q_GFRAW "QTYPE q" | |||||
Not Done Inline ActionsThis isn't a great name for a comparison function -- I saw it, and I assumed it returned a negative version of the input number. The option is to have all of the check macros there use Q_IS<op>, and I'm not sure how well that works out either. sef: This isn't a great name for a comparison function -- I saw it, and I assumed it returned a… | |||||
Done Inline ActionsHm. How about Q_LTZ()? trasz: Hm. How about Q_LTZ()? | |||||
Not Done Inline ActionsIs there any reason not to just use Q_LT, Q_LE, Q_GT, Q_GE, etc? cem: Is there any reason not to just use `Q_LT`, `Q_LE`, `Q_GT`, `Q_GE`, etc? | |||||
Done Inline ActionsIt kind of follows the convention with QMULQ (vs QMULI) et al. On the other hand this doesn't seem to be very consistent. I'll think about it some more. trasz: It kind of follows the convention with QMULQ (vs QMULI) et al. On the other hand this doesn't… | |||||
Not Done Inline ActionsFYI as background on my choice of naming convention... Q_ is intended as a library-wide prefix, and after the prefix, the placement of the numeric type identifiers from the man page ({Q | I | N}TYPE) indicates the types of the operands e.g. Q_Q<op>Q indicates the function operates on a Q number as its first numeric type argument (as opposed to a stdint or generic numeric type) and Q number as its second numeric type argument. Q_QFRACI by contrast operates on a Q first arg and stdint supplemental args. So Q_QGTQ compares 2 Q numbers, while a hypothetical Q_QGTI would target cross-type comparison. lstewart: FYI as background on my choice of naming convention... Q_ is intended as a library-wide prefix… | |||||
.Ft ITYPE | |||||
.Fn Q_GFABSVAL "QTYPE q" | |||||
.Ft ITYPE | |||||
.Fn Q_GFVAL "QTYPE q" | |||||
.Ft QTYPE | |||||
.Fn Q_SFVAL "QTYPE q" "ITYPE fv" | |||||
.Ss Miscellaneous functions/variables. | |||||
.Fd Q_NCBITS | |||||
.Ft __typeof(q) | |||||
.Fn Q_BT "QTYPE q" | |||||
.Ft ITYPE | |||||
.Fn Q_TC "QTYPE q" "ITYPE v" | |||||
.Ft uint32_t | |||||
.Fn Q_NTBITS "QTYPE q" | |||||
.Ft uint32_t | |||||
.Fn Q_NFCBITS "QTYPE q" | |||||
.Ft uint32_t | |||||
.Fn Q_MAXNFBITS "QTYPE q" | |||||
.Ft uint32_t | |||||
.Fn Q_NFBITS "QTYPE q" | |||||
.Ft uint32_t | |||||
.Fn Q_NIBITS "QTYPE q" | |||||
.Ft uint32_t | |||||
.Fn Q_RPSHFT "QTYPE q" | |||||
.Ft NTYPE | |||||
.Fn Q_ABS "NTYPE n" | |||||
.Ft uint32_t | |||||
.Fn Q_MAXSTRLEN "QTYPE q" "int base" | |||||
.Ft char * | |||||
.Fn Q_TOSTR "QTYPE q" "int prec" "int base" "char *s" "int slen" | |||||
.Ft ITYPE | |||||
.Fn Q_SHL "QTYPE q" "ITYPE iv" | |||||
.Ft ITYPE | |||||
.Fn Q_SHR "QTYPE q" "ITYPE iv" | |||||
.Ft char *, ... | |||||
.Fn Q_DEBUG "QTYPE q" "char *prefmt" "char *postfmt" "incfmt" | |||||
.Sh DESCRIPTION | |||||
The | |||||
.Nm | |||||
data types and APIs support fixed-point math based on the | |||||
.Dq Q | |||||
number format. | |||||
The APIs have been built around the following data types: | |||||
.Vt s8q_t , | |||||
.Vt u8q_t , | |||||
.Vt s16q_t , | |||||
.Vt u16q_t , | |||||
.Vt s32q_t , | |||||
.Vt u32q_t , | |||||
.Vt s64q_t , | |||||
and | |||||
.Vt u64q_t , | |||||
which are referred to generically in the earlier API definitions as | |||||
.Fa QTYPE . | |||||
The | |||||
.Fa ITYPE | |||||
refers to the | |||||
.Xr stdint 7 | |||||
integer types. | |||||
.Fa NTYPE | |||||
is used to refer to any numeric type and is therefore a superset of | |||||
.Fa QTYPE | |||||
and | |||||
.Fa ITYPE . | |||||
.Pp | |||||
This scheme can represent Q numbers with | |||||
.Bq 2, 4, 6, 8, 16, 32, 48 | |||||
bits of precision after the binary radix point, | |||||
depending on the | |||||
.Fa rpshft | |||||
argument to | |||||
.Fn Q_INI . | |||||
The number of bits available for the integral component is not explicitly | |||||
specified, and implicitly consumes the remaining available bits of the chosen Q | |||||
data type. | |||||
.Pp | |||||
For more details, see the | |||||
.Sx IMPLEMENTATION DETAILS | |||||
below. | |||||
.Ss Functions which create/initialise a Q number. | |||||
.Fn Q_INI | |||||
initialises a Q number with the supplied integral value | |||||
.Fa iv | |||||
and with appropriate control bits based on the requested radix shift point | |||||
.Fa rpshft . | |||||
.Ss Numeric functions which operate on two Q numbers. | |||||
The | |||||
.Fn Q_QADDQ , | |||||
.Fn Q_QDIVQ , | |||||
.Fn Q_QMULQ , | |||||
and | |||||
.Fn Q_QSUBQ | |||||
functions add, divide, multiply or subtract | |||||
.Fa b | |||||
to/by/from | |||||
.Fa a | |||||
respectively, storing the result in | |||||
.Fa a . | |||||
.Pp | |||||
The | |||||
.Fn Q_NORMPREC | |||||
function attempts to normalise the precision of | |||||
.Fa a | |||||
and | |||||
.Fa b | |||||
if they differ. | |||||
The greater of the two precisions is preferred if possible, unless that would | |||||
truncate integer component data for the other operand, in which case the highest | |||||
precision that preserves the integer component of both | |||||
.Fa a | |||||
and | |||||
.Fa b | |||||
is selected. | |||||
.Pp | |||||
The | |||||
.Fn Q_QMAXQ | |||||
and | |||||
.Fn Q_QMINQ | |||||
functions return the larger or smaller of | |||||
.Fa a | |||||
and | |||||
.Fa b | |||||
respectively. | |||||
.Pp | |||||
The | |||||
.Fn Q_QCLONEQ | |||||
and | |||||
.Fn Q_QCPYVALQ | |||||
functions attempt to store identical or representational copies of | |||||
.Fa r , | |||||
in | |||||
.Fa l | |||||
respectively. | |||||
An identical Q number produced by cloning copies the control bits as well as the | |||||
verbatim integer/fractional bits. | |||||
A representational copy only copies the values of | |||||
.Fa r Ap s | |||||
integer and fractional bits, representing them in the bits available per | |||||
.Fa l Ap s | |||||
Q format. | |||||
.Ss Numeric functions which apply integers to a Q number. | |||||
The | |||||
.Fn Q_QADDI , | |||||
.Fn Q_QDIVI , | |||||
.Fn Q_QMULI | |||||
and | |||||
.Fn Q_QSUBI | |||||
functions add, divide, multiply or subtract | |||||
.Fa b | |||||
to/by/from | |||||
.Fa a | |||||
respectively, storing the result in | |||||
.Fa a . | |||||
.Pp | |||||
The | |||||
.Fn Q_QFRACI | |||||
function computes the fraction | |||||
.Fa n | |||||
divided by | |||||
.Fa d | |||||
and stores the fixed-point result in | |||||
.Fa q . | |||||
.Pp | |||||
The | |||||
.Fn Q_QCPYVALI | |||||
function overwrites | |||||
.Fa q Ap s | |||||
integer and fractional bits with the Q representation of integer value | |||||
.Fa i . | |||||
.Ss Numeric functions which operate on a single Q number. | |||||
The | |||||
.Fn Q_QABS | |||||
function returns an absolute value representation of | |||||
.Fa q . | |||||
.Pp | |||||
The | |||||
.Fn Q_Q2D | |||||
and | |||||
Done Inline ActionsThis will print the binary-encoded representation of the fractional bits as decimal, which I don't think is what you're trying to demonstrate here. lstewart: This will print the binary-encoded representation of the fractional bits as decimal, which I… | |||||
Done Inline ActionsD'oh, the same bug as before, just in reverse. Thanks, fixed. trasz: D'oh, the same bug as before, just in reverse. Thanks, fixed. | |||||
.Fn Q_Q2F | |||||
functions return the double and float representations of | |||||
.Fa q | |||||
respectively. | |||||
.Ss Comparison and logic functions. | |||||
.Fn Q_SIGNED | |||||
returns | |||||
.Ft true | |||||
if the numeric data type passed in as | |||||
.Fa n | |||||
is signed, or | |||||
.Ft false | |||||
Done Inline ActionsQ_MAXSTRLEN seems to take 2 arguments now, q and base. I think think needs to be changed to: to work (base 10 matching the Q_TOSTR with base 10 you are doing below) allanjude: Q_MAXSTRLEN seems to take 2 arguments now, q and base.
I think think needs to be changed to… | |||||
otherwise. | |||||
.Fn Q_LTZ | |||||
returns | |||||
.Ft true | |||||
if the numeric value | |||||
passed in as | |||||
.Fa n | |||||
is negative | |||||
.Pq requires types which use the MSB as the sign bit , | |||||
or | |||||
.Ft false | |||||
otherwise. | |||||
.Pp | |||||
.Fn Q_PRECEQ | |||||
returns | |||||
.Ft true | |||||
if the number of | |||||
.Fa a | |||||
and | |||||
.Fa b | |||||
fractional bits is the same, | |||||
.Ft false | |||||
otherwise. | |||||
.Pp | |||||
The | |||||
.Fn Q_QLTQ , | |||||
.Fn Q_QLEQ , | |||||
.Fn Q_QGTQ , | |||||
.Fn Q_QGEQ , | |||||
.Fn Q_QEQ | |||||
and | |||||
.Fn Q_QNEQ | |||||
functions compare two Q numbers, returning | |||||
.Ft true | |||||
if | |||||
.Fa a | |||||
is less than, less than or equal to, greater than, greater than or equal to, | |||||
equal to, or not equal to | |||||
.Fa b | |||||
respectively, or | |||||
.Ft false | |||||
otherwise. | |||||
The integral and fractional values are used to perform the comparison, without | |||||
explicit concern for the underlying number of integer versus fractional bits. | |||||
.Pp | |||||
.Fn Q_OFLOW | |||||
returns | |||||
.Ft true | |||||
if integer value | |||||
.Fa iv | |||||
cannot be stored in | |||||
.Fa q | |||||
without truncation, or false otherwise. | |||||
.Pp | |||||
.Fn Q_RELPREC | |||||
returns the relative precision of | |||||
.Fa a | |||||
versus | |||||
.Fa b . | |||||
In terms of | |||||
.Em Qm.n | |||||
notation, this function returns the difference between the | |||||
.Em n | |||||
values of | |||||
.Fa a | |||||
and | |||||
.Fa b . | |||||
For example, a return value of +4 means that | |||||
.Fa a | |||||
has an additional 4 bits of fractional precision compared to | |||||
.Fa b . | |||||
.Ss Functions which manipulate the Q bits holding control/sign data. | |||||
.Fn Q_SIGNSHFT | |||||
gets the bit position of | |||||
.Fa q Ap s | |||||
sign bit relative to bit zero. | |||||
.Fn Q_SSIGN | |||||
sets the sign bit of | |||||
.Fa q | |||||
based on the boolean | |||||
.Fa isneg . | |||||
.Pp | |||||
.Fn Q_CRAWMASK | |||||
and | |||||
.Fn Q_SRAWMASK | |||||
return | |||||
Not Done Inline ActionsIs this required by convention around Q numbers, or how was this set of sizes chosen? It seems like an odd scale of bits if it is not mandated by some existing convention. E.g., is 2 bits of suffix especially valuable? Is it necessary that the fractional parts are all of size divisible by 2? For example, you could instead have a non-linear relationship and instead map the lower 3 bits into some 8-entry lookup table of a non-linear function; e.g., floor((x+1)² * 0.791) + 1 ⇒ [4, 8, 13, 20, 29, 39, 51, 64]. You could substitute some other function to stack more of the widths in the low end of the spectrum, if that is desired. (Is it actually valuable or even possible to represent qnums with 64 bits of fractional part? It seems like 64 bits is aspirational, due to the maximum unsigned QTYPE u64q_t and the minimum 3 control bits; there are only 61 bits available for precision.) cem: Is this required by convention around Q numbers, or how was this set of sizes chosen? It seems… | |||||
Done Inline ActionsTo be honest... I don't know. I'm not the original author. The current encoding does make sense - it's quite compact and does not need any additional table lookups (ie memory accesses), though. I think you're right regarding the 64 bits - I've removed this part. trasz: To be honest... I don't know. I'm not the original author. The current encoding does make… | |||||
Not Done Inline ActionsAn 8-entry LUT can be stored in 8 bytes; it probably would not generate additional memory accesses (i.e., compiler would store in the instruction stream, or it would already be present in cache). I wouldn't worry about it from a memory access perspective. cem: An 8-entry LUT can be stored in 8 bytes; it probably would not generate additional memory… | |||||
.Fa q Ns -specific | |||||
bit masks for | |||||
.Fa q Ap s | |||||
control bits and sign bit respectively. | |||||
.Pp | |||||
.Fn Q_GCRAW | |||||
and | |||||
.Fn Q_GCVAL | |||||
get the raw masked control bits and value of | |||||
.Fa q Ap s | |||||
control bits respectively. | |||||
.Fn Q_SCVAL | |||||
sets | |||||
.Fa q Ap s | |||||
control bits to the value | |||||
.Fa cv . | |||||
.Ss Functions which manipulate the combined integer/fractional data bits. | |||||
.Fn Q_IFRAWMASK | |||||
returns a | |||||
.Fa q Ns -specific | |||||
bit mask for | |||||
.Fa q Ap s | |||||
combined integer and fractional data bits. | |||||
.Fn Q_IFVALIMASK | |||||
and | |||||
.Fn Q_IFVALFMASK | |||||
return | |||||
.Fa q Ns -specific | |||||
bit masks for the integer and fractional bits of | |||||
.Fa q Ap s | |||||
combined integer and fractional data bits value, i.e., are applicable to the | |||||
values returned by | |||||
.Fn Q_GIFABSVAL | |||||
and | |||||
.Fn Q_GIFVAL . | |||||
.Pp | |||||
.Fn Q_GIFRAW | |||||
returns | |||||
.Fa q Ap s | |||||
raw masked integer/fractional data bits. | |||||
.Pp | |||||
.Fn Q_GIFABSVAL | |||||
and | |||||
.Fn Q_GIFVAL | |||||
return the absolute and real values of | |||||
.Fa q Ap s | |||||
integer/fractional data bits respectively. | |||||
.Pp | |||||
.Fn Q_SIFVAL | |||||
sets | |||||
.Fa q Ap s | |||||
combined integer/fractional data bits to the value | |||||
.Fa ifv , | |||||
whereas | |||||
.Fn Q_SIFVALS | |||||
independently sets | |||||
.Fa q Ap s | |||||
integer and fractional data bits to the separate values | |||||
.Fa iv | |||||
and | |||||
.Fa fv . | |||||
.Ss Functions which manipulate the integer data bits. | |||||
.Fn Q_IRAWMASK | |||||
returns a | |||||
.Fa q Ns -specific | |||||
bit mask for | |||||
.Fa q Ap s | |||||
integer data bits. | |||||
.Pp | |||||
.Fn Q_GIRAW | |||||
returns | |||||
.Fa q Ap s | |||||
raw masked integer data bits. | |||||
.Pp | |||||
.Fn Q_GIABSVAL | |||||
and | |||||
.Fn Q_GIVAL | |||||
return the absolute and real values of | |||||
.Fa q Ap s | |||||
integer data bits respectively. | |||||
.Pp | |||||
.Fn Q_SIVAL | |||||
sets | |||||
.Fa q Ap s | |||||
integer data bits to the value | |||||
.Fa iv . | |||||
.Ss Functions which manipulate the fractional data bits. | |||||
.Fn Q_FRAWMASK | |||||
returns a | |||||
.Fa q Ns -specific | |||||
bit mask for | |||||
.Fa q Ap s | |||||
fractional data bits. | |||||
.Pp | |||||
.Fn Q_GFRAW | |||||
returns | |||||
.Fa q Ap s | |||||
raw masked fractional data bits. | |||||
.Pp | |||||
.Fn Q_GFABSVAL | |||||
and | |||||
.Fn Q_GFVAL | |||||
return the absolute and real values of | |||||
.Fa q Ap s | |||||
fractional data bits respectively. | |||||
.Pp | |||||
.Fn Q_SFVAL | |||||
sets | |||||
.Fa q Ap s | |||||
fractional data bits to the value | |||||
.Fa fv . | |||||
.Ss Miscellaneous functions/variables. | |||||
The | |||||
.Dv Q_NCBITS | |||||
defined constant specifies the number of reserved control bits, currently 3. | |||||
.Fn Q_NTBITS , | |||||
.Fn Q_NFCBITS , | |||||
.Fn Q_MAXNFBITS , | |||||
.Fn Q_NFBITS | |||||
and | |||||
.Fn Q_NIBITS | |||||
return the | |||||
.Fa q Ns -specific | |||||
count of total, control-encoded fractional, maximum fractional, effective | |||||
fractional, and integer bits applicable to | |||||
.Fa q | |||||
respectively. | |||||
.Pp | |||||
.Fn Q_BT | |||||
returns the C data type of | |||||
.Fa q , | |||||
while | |||||
.Fn Q_TC | |||||
returns | |||||
.Fa v | |||||
type casted to the C data type of | |||||
.Fa q . | |||||
.Pp | |||||
.Fn Q_RPSHFT | |||||
returns the bit position of | |||||
.Fa q Ap s | |||||
binary radix point relative to bit zero. | |||||
.Pp | |||||
.Fn Q_ABS | |||||
Returns the absolute value of any standard numeric type | |||||
.Pq that uses the MSB as a sign bit, but not Q numbers | |||||
passed in as | |||||
.Fa n . | |||||
The function is signed/unsigned type safe. | |||||
.Pp | |||||
.Fn Q_SHL | |||||
and | |||||
.Fn Q_SHR | |||||
return the integral value | |||||
.Fa v | |||||
left or right shifted by the appropriate amount for | |||||
.Fa q . | |||||
.Pp | |||||
.Fn Q_MAXSTRLEN | |||||
calculates the maximum number of characters that may be required to render the | |||||
C-string representation of | |||||
.Fa q | |||||
with numeric base | |||||
.Fa base . | |||||
.Pp | |||||
.Fn Q_TOSTR | |||||
renders the C-string representation of | |||||
.Fa q | |||||
with numeric base | |||||
.Fa base | |||||
and fractional precision | |||||
.Fa prec | |||||
into | |||||
.Fa s | |||||
which has an available capacity of | |||||
.Fa slen | |||||
characters. | |||||
.Fa base | |||||
must be in range | |||||
.Bq 2,16 . | |||||
Specifying | |||||
.Fa prec | |||||
as -1 renders the number's fractional component with maximum precision. | |||||
If | |||||
.Fa slen | |||||
is greater than zero but insufficient to hold the complete C-string, the '\\0' | |||||
C-string terminator will be written to | |||||
.Fa *s , | |||||
thereby returning a zero length C-string. | |||||
.Pp | |||||
.Fn Q_DEBUG | |||||
returns a format string and associated data suitable for printf-like rendering | |||||
of debugging information pertaining to | |||||
.Fa q . | |||||
If either | |||||
.Fa prefmt | |||||
and/or | |||||
.Fa postfmt | |||||
are specified, they are prepended and appended to the resulting format string | |||||
respectively. | |||||
The | |||||
.Fa incfmt | |||||
boolean specifies whether to include | |||||
.Pq Vt true | |||||
or exclude | |||||
.Pq Vt false | |||||
the raw format string itself in the debugging output. | |||||
.Sh IMPLEMENTATION DETAILS | |||||
The | |||||
.Nm | |||||
data types and APIs support fixed-point math based on the | |||||
.Dq Q | |||||
number format. | |||||
This implementation uses the Q notation | |||||
.Em Qm.n , | |||||
where | |||||
.Em m | |||||
specifies the number of bits for integral data | |||||
.Pq excluding the sign bit for signed types , | |||||
and | |||||
.Em n | |||||
specifies the number of bits for fractional data. | |||||
.Pp | |||||
The APIs have been built around the following q_t derived data types: | |||||
.Bd -literal -offset indent | |||||
typedef int8_t s8q_t; | |||||
typedef uint8_t u8q_t; | |||||
typedef int16_t s16q_t; | |||||
typedef uint16_t u16q_t; | |||||
typedef int32_t s32q_t; | |||||
typedef uint32_t u32q_t; | |||||
typedef int64_t s64q_t; | |||||
typedef uint64_t u64q_t; | |||||
.Ed | |||||
.Pp | |||||
These types are referred to generically in the earlier API definitions as | |||||
.Fa QTYPE , | |||||
while | |||||
.Fa ITYPE | |||||
refers to the | |||||
.Xr stdint 7 | |||||
integer types the Q data types are derived from. | |||||
.Fa NTYPE | |||||
is used to refer to any numeric type and is therefore a superset of | |||||
.Fa QTYPE | |||||
and | |||||
.Fa ITYPE . | |||||
.Pp | |||||
The 3 least significant bits | |||||
.Pq LSBs | |||||
of all q_t data types are reserved for embedded control data: | |||||
.Bl -dash | |||||
.It | |||||
bits 1-2 specify the binary radix point shift index operand, with 00,01,10,11 == | |||||
1,2,3,4. | |||||
.It | |||||
bit 3 specifies the radix point shift index operand multiplier as 2 | |||||
.Pq 0 | |||||
or 16 | |||||
.Pq 1 . | |||||
.El | |||||
.Pp | |||||
This scheme can therefore represent Q numbers with | |||||
.Bq 2,4,6,8,16,32,48,64 | |||||
bits of precision after the binary radix point. | |||||
The number of bits available for the integral component is not explicitly | |||||
specified, and implicitly consumes the remaining available bits of the chosen Q | |||||
data type. | |||||
.Pp | |||||
Additionally, the most significant bit | |||||
.Pq MSB | |||||
of signed Q types stores the sign bit, with bit value 0 representing a positive | |||||
number and bit value 1 representing a negative number. | |||||
Negative numbers are stored as absolute values with the sign bit set, rather | |||||
than the more typical two's complement representation. | |||||
This avoids having to bit shift negative numbers, which can result in undefined | |||||
behaviour from some compilers. | |||||
.Pp | |||||
This binary representation used for Q numbers therefore comprises a set of | |||||
distinct data bit types and associated bit counts. | |||||
Data bit types/labels, listed in LSB to MSB order, are: control | |||||
.Sq C , | |||||
fractional | |||||
.Sq F , | |||||
integer | |||||
.Sq I | |||||
and sign | |||||
.Sq S . | |||||
The following example illustrates the binary representation of a Q20.8 number | |||||
represented using a s32q_t variable: | |||||
.Bd -literal -offset indent | |||||
M L | |||||
S S | |||||
B B | |||||
3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 | |||||
1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 | |||||
S I I I I I I I I I I I I I I I I I I I I F F F F F F F F C C C | |||||
.Ed | |||||
.Pp | |||||
Important bit counts are: total, control, control-encoded fractional, maximum | |||||
fractional, effective fractional and integer bits. | |||||
.Pp | |||||
The count of total bits is derived from the size of the q_t data type. | |||||
For example, a s32q_t has 32 total bits. | |||||
.Pp | |||||
The count of control-encoded fractional bits is derived from calculating the | |||||
number of fractional bits per the control bit encoding scheme. | |||||
For example, the control bits binary value of 101 encodes a fractional bit | |||||
count of 2 x 16 = 32 fractional bits. | |||||
.Pp | |||||
The count of maximum fractional bits is derived from the difference between the | |||||
counts of total bits and control/sign bits. | |||||
For example, a s32q_t has a maximum of 32 - 3 - 1 = 28 fractional bits. | |||||
.Pp | |||||
The count of effective fractional bits is derived from the minimum of the | |||||
control-encoded fractional bits and the maximum fractional bits. | |||||
For example, a s32q_t with 32 control-encoded fractional bits is effectively | |||||
limited to 28 fractional bits. | |||||
.Pp | |||||
The count of integer bits is derived from the difference between the counts of | |||||
total bits and all other non-integer data bits | |||||
.Pq the sum of control, fractional and sign bits. | |||||
For example, a s32q_t with 8 effective fractional bits has 32 - 3 - 8 - 1 = 20 integer | |||||
bits. | |||||
The count of integer bits can be zero if all available numeric data bits have | |||||
been reserved for fractional data, e.g., when the number of control-encoded | |||||
fractional bits is greater than or equal to the underlying Q data type's maximum | |||||
fractional bits. | |||||
.Sh RETURN VALUES | |||||
.Fn Q_INI | |||||
returns the initialised Q number which can be used to chain initialise | |||||
additional Q numbers. | |||||
The | |||||
.Fn Q_QADDQ , | |||||
.Fn Q_QDIVQ , | |||||
.Fn Q_QMULQ , | |||||
.Fn Q_QSUBQ | |||||
.Fn Q_NORMPREC , | |||||
.Fn Q_QCLONEQ | |||||
and | |||||
.Fn Q_QCPYVALQ | |||||
functions return 0 on success, or an errno on failure. | |||||
.Er EINVAL | |||||
is returned for divide-by-zero. | |||||
.Er EOVERFLOW | |||||
and | |||||
.Er ERANGE | |||||
are returned for overflow and underflow respectively. | |||||
.Pp | |||||
The | |||||
.Fn Q_QMAXQ | |||||
and | |||||
.Fn Q_QMINQ | |||||
functions return the numerically larger or smaller of their two inputs | |||||
respectively. | |||||
The | |||||
.Fn Q_QADDI , | |||||
.Fn Q_QDIVI , | |||||
.Fn Q_QMULI , | |||||
.Fn Q_QSUBI , | |||||
.Fn Q_QFRACI | |||||
and | |||||
.Fn Q_QCPYVALI | |||||
functions return 0 on success, or an errno on failure. | |||||
.Er EINVAL | |||||
is returned for divide-by-zero. | |||||
.Er EOVERFLOW | |||||
and | |||||
.Er ERANGE | |||||
are returned for overflow and underflow respectively. | |||||
The | |||||
.Fn Q_QABS | |||||
function returns a QTYPE that is identical to that of | |||||
.Fa q . | |||||
The | |||||
.Fn Q_SIGNED , | |||||
.Fn Q_LTZ , | |||||
.Fn Q_PRECEQ , | |||||
.Fn Q_QLTQ , | |||||
.Fn Q_QLEQ , | |||||
.Fn Q_QGTQ , | |||||
.Fn Q_QGEQ , | |||||
.Fn Q_QEQ , | |||||
.Fn Q_QNEQ | |||||
and | |||||
.Fn Q_OFLOW | |||||
functions return expressions that evaluate to boolean | |||||
.Vt true | |||||
or | |||||
.Vt false . | |||||
.Pp | |||||
.Fn Q_RELPREC | |||||
returns the relative precision difference as a signed integer. | |||||
.Fn Q_SIGNSHFT | |||||
returns the sign bit's position as an integer. | |||||
.Pp | |||||
.Fn Q_SSIGN | |||||
returns the value of | |||||
.Fa q | |||||
post change. | |||||
.Pp | |||||
.Fn Q_CRAWMASK , | |||||
.Fn Q_SRAWMASK , | |||||
.Fn Q_GCRAW | |||||
and | |||||
.Fn Q_GCVAL | |||||
return their respective values as integers of the same underlying ITYPE as | |||||
.Fa q . | |||||
.Pp | |||||
.Fn Q_SCVAL | |||||
returns the value of | |||||
.Fa q | |||||
post change. | |||||
.Fn Q_IFRAWMASK , | |||||
.Fn Q_IFVALIMASK , | |||||
.Fn Q_IFVALFMASK , | |||||
.Fn Q_GIFABSVAL , | |||||
.Fn Q_GIFVAL , | |||||
.Fn Q_GIFRAW , | |||||
.Fn Q_GIFABSVAL | |||||
and | |||||
.Fn Q_GIFVAL | |||||
return their respective values as integers of the same underlying ITYPE as | |||||
.Fa q . | |||||
.Pp | |||||
.Fn Q_SIFVAL | |||||
and | |||||
.Fn Q_SIFVALS | |||||
return the value of | |||||
.Fa q | |||||
post change. | |||||
.Fn Q_IRAWMASK , | |||||
.Fn Q_GIRAW , | |||||
.Fn Q_GIABSVAL | |||||
and | |||||
.Fn Q_GIVAL | |||||
return their respective values as integers of the same underlying ITYPE as | |||||
.Fa q . | |||||
.Pp | |||||
.Fn Q_SIVAL | |||||
returns the value of | |||||
.Fa q | |||||
post change. | |||||
.Fn Q_FRAWMASK , | |||||
.Fn Q_GFRAW , | |||||
.Fn Q_GFABSVAL | |||||
and | |||||
.Fn Q_GFVAL | |||||
return their respective values as integers of the same underlying ITYPE as | |||||
.Fa q . | |||||
.Pp | |||||
.Fn Q_SFVAL | |||||
returns the value of | |||||
.Fa q | |||||
post set. | |||||
.Fn Q_TOSTR | |||||
returns a pointer to the '\\0' C-string terminator appended to | |||||
.Fa s | |||||
after the rendered numeric data, or NULL on buffer overflow. | |||||
.Sh EXAMPLES | |||||
.Ss Calculating area of a circle with r=4.2 and rpshft=16 | |||||
.Bd -literal -offset indent | |||||
u64q_t a, pi, r; | |||||
a = pi = Q_INI(&r, 0, 16); | |||||
Q_SIFVALS(pi, 3, 14159); | |||||
Q_SIFVALS(r, 4, 2); | |||||
Q_QCLONEQ(&a, r); | |||||
Q_QMULQ(&a, r); | |||||
Q_QMULQ(&a, pi); | |||||
printf("%lu.%lu\\n", Q_GIVAL(a), Q_GFVAL(a)); | |||||
.Ed | |||||
.Ss Debugging | |||||
Declare a Q20.8 s32q_t number | |||||
.Fa s32 , | |||||
initialise it with the fixed-point value for 5/3, and render a debugging | |||||
representation of the variable | |||||
.Pq including its full precision decimal C-string representation , | |||||
to the console: | |||||
.Bd -literal -offset indent | |||||
s32q_t s32; | |||||
Q_INI(&s32, 0, 8); | |||||
Q_QFRACI(&s32, 5, 3); | |||||
char buf[Q_MAXSTRLEN(s32)]; | |||||
Q_TOSTR(s32, -1, 10, buf, sizeof(buf)); | |||||
printf(Q_DEBUG(s32, "", "\\n\\ttostr=%s\\n\\n", 0), buf); | |||||
.Ed | |||||
.Pp | |||||
The above code outputs the following to the console: | |||||
.Bd -literal -offset indent | |||||
"s32"@0x7fffffffe7d4 | |||||
type=s32q_t, Qm.n=Q20.8, rpshft=11, imin=0xfff00001, \\ | |||||
imax=0xfffff | |||||
qraw=0x00000d53 | |||||
imask=0x7ffff800, fmask=0x000007f8, cmask=0x00000007, \\ | |||||
ifmask=0x7ffffff8 | |||||
iraw=0x00000800, iabsval=0x1, ival=0x1 | |||||
fraw=0x00000550, fabsval=0xaa, fval=0xaa | |||||
tostr=1.664 | |||||
.Ed | |||||
.Pp | |||||
Note: The | |||||
.Qq \e | |||||
present in the rendered output above indicates a manual line break inserted to | |||||
keep the man page within 80 columns and is not part of the actual output. | |||||
.Sh SEE ALSO | |||||
.Xr errno 2 , | |||||
.Xr math 3 , | |||||
.Xr stdint 7 | |||||
.Sh HISTORY | |||||
The | |||||
.Nm | |||||
functions first appeared in | |||||
.Fx 13.0 . | |||||
.Sh AUTHORS | |||||
.An -nosplit | |||||
The | |||||
.Nm | |||||
functions and this manual page were written by | |||||
.An Lawrence Stewart Aq Mt lstewart@FreeBSD.org | |||||
and sponsored by Netflix, Inc. | |||||
Not Done Inline ActionsTypical style is .An Lawrence Stewart Aq Mt lstewart@FreeBSD.org (I.e., add Mt) cem: Typical style is
```
.An Lawrence Stewart Aq Mt lstewart@FreeBSD.org
```
(I.e., add `Mt`) | |||||
Done Inline ActionsThis isn't a helpful BUGS section. Be specific about what functions and what the worst case current error rate is, and what the best case error rate should be, or just drop the section. cem: This isn't a helpful BUGS section. Be specific about what functions and what the worst case… |
What is that q doing there?