QMATH(3)

๐Ÿ“ฆ version 15.1, in freebsd 14.5, freebsd 15.1, nixpkgs unstable

๐Ÿ’… qmath โ€” QMATH(3) ยท Library Functions Manual ๐Ÿ’…

โœจ NAME โœจ

qmath โ€” fixed-point math library based on the โ€œQโ€ number format

๐ŸŒธ SYNOPSIS ๐ŸŒธ

#include <sys/qmath.h>

๐Ÿ’– DESCRIPTION ๐Ÿ’–

Okay so the qmath data types and APIs support fixed-point math based on the โ€œQโ€ number format. The APIs have been built around these data types: s8q_t, u8q_t, s16q_t, u16q_t, s32q_t, u32q_t, s64q_t, and u64q_t, which are referred to generically in the earlier API definitions as QTYPE. The ITYPE refers to the stdint(7) integer types. NTYPE is used to refer to any numeric type and is therefore a superset of QTYPE and ITYPE. Periodt.

This scheme can represent Q numbers with [2, 4, 6, 8, 16, 32, 48] bits of precision after the binary radix point, depending on the rpshft argument to 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. No cap.

Operations on Q numbers maintain the precision of their arguments. The fractional component is truncated to fit into the destination, with no rounding. None of the operations is affected by the floating-point environment.

For more details, see the โ€œIMPLEMENTATION DETAILSโ€ below. We'll get there, bestie ๐Ÿ’–

๐ŸŽ€ LIST OF FUNCTIONS ๐ŸŽ€

๐Ÿฆ‹ Functions which create/initialise a Q number ๐Ÿฆ‹

  • Q_INI(3) โ€” initialise a Q number

๐ŸŒผ Numeric functions which operate on two Q numbers ๐ŸŒผ

๐ŸŒบ Numeric functions which apply integers to a Q number ๐ŸŒบ

๐Ÿ’ซ Numeric functions which operate on a single Q number ๐Ÿ’ซ

๐Ÿ”ฅ Comparison and logic functions ๐Ÿ”ฅ

๐Ÿ‘‘ Functions which manipulate the control/sign data bits ๐Ÿ‘‘

๐ŸŒˆ Functions which manipulate the combined integer/fractional data bits ๐ŸŒˆ

โญ Functions which manipulate the integer data bits โญ

๐Ÿฆ‹ Functions which manipulate the fractional data bits ๐Ÿฆ‹

๐Ÿ“ Miscellaneous functions/variables ๐Ÿ“

๐Ÿงš IMPLEMENTATION DETAILS ๐Ÿงš

Now for the deep lore, bestie. The qmath data types and APIs support fixed-point math based on the โ€œQโ€ number format. This implementation uses the Q notation Qm.n, where m specifies the number of bits for integral data (excluding the sign bit for signed types), and n specifies the number of bits for fractional data.

The APIs have been built around the following q_t derived data types:

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;

These types are referred to generically in the earlier API definitions as QTYPE, while ITYPE refers to the stdint(7) integer types the Q data types are derived from. NTYPE is used to refer to any numeric type and is therefore a superset of QTYPE and ITYPE.

The 3 least significant bits (LSBs) of all q_t data types are reserved for embedded control data:

  • bits 1-2 specify the binary radix point shift index operand, with 00,01,10,11 == 1,2,3,4.
  • bit 3 specifies the radix point shift index operand multiplier as 2 (0) or 16 (1).

This scheme can therefore represent Q numbers with [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.

Additionally, the most significant bit (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.

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 โ€˜Cโ€™, fractional โ€˜Fโ€™, integer โ€˜Iโ€™ and sign โ€˜Sโ€™. The following example illustrates the binary representation of a Q20.8 number represented using a s32q_t variable:

             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

Important bit counts are: total, control, control-encoded fractional, maximum fractional, effective fractional and integer bits.

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.

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.

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.

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.

The count of integer bits is derived from the difference between the counts of total bits and all other non-integer data bits (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.

๐Ÿ“ EXAMPLES ๐Ÿ“

๐Ÿงฎ Calculating area of a circle with r=4.2 and rpshft=16 ๐Ÿงฎ

u64q_t a, pi, r;
char buf[32]

Q_INI(&a, 0, 0, 16);
Q_INI(&pi, 3, 14159, 16);
Q_INI(&r, 4, 2, 16);

Q_QCLONEQ(&a, r);
Q_QMULQ(&a, r);
Q_QMULQ(&a, pi);

Q_TOSTR(a, -1, 10, buf, sizeof(buf));
printf("%s\n", buf);

๐Ÿ› Debugging ๐Ÿ›

Declare a Q20.8 s32q_t number s32, initialise it with the fixed-point value for 5/3, and render a debugging representation of the variable (including its full precision decimal C-string representation), to the console:

s32q_t s32;
Q_INI(&s32, 0, 0, 8);
Q_QFRACI(&s32, 5, 3);
char buf[Q_MAXSTRLEN(s32, 10)];
Q_TOSTR(s32, -1, 10, buf, sizeof(buf));
printf(Q_DEBUG(s32, "", "\n\ttostr=%s\n\n", 0), buf);

The above code outputs the following to the console:

"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

Note: The \ 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.

๐Ÿ’ซ SEE ALSO ๐Ÿ’ซ

ok so if you wanna go deeper (and honestly bestie, you should, the lore is real), go peek at these:

  • errno(2) โ€” the error-number girlie, for when things go sideways
  • math(3) โ€” the classic math library, your OG
  • Q_FRAWMASK(3) โ€” fractional raw mask things
  • Q_IFRAWMASK(3) โ€” integer raw mask things, the sibling
  • Q_INI(3) โ€” initialization, how you actually start one of these bad boys
  • Q_IRAWMASK(3) โ€” raw mask, integer flavour
  • Q_QABS(3) โ€” absolute value, but qmath-flavoured
  • Q_QADDI(3) โ€” adding ints, qmath style
  • Q_QADDQ(3) โ€” adding qmath numbers together
  • Q_SIGNED(3) โ€” signed stuff, the whole vibe
  • Q_SIGNSHFT(3) โ€” sign shifting, sounds iconic
  • stdint(7) โ€” for all the fixed-width integer tea ๐Ÿซ–

they're all linked up, it's giving family reunion, iykyk ๐Ÿ’…


๐Ÿ•ฐ๏ธ HISTORY ๐Ÿ•ฐ๏ธ

so the qmath functions first appeared in FreeBSD 13.0 โ€” that's their debut era, their origin story, their main character entrance โœจ not me being obsessed with a release version, but like, it's literally where they were born fr fr ๐Ÿ’–


๐Ÿ‘‘ AUTHORS ๐Ÿ‘‘

the qmath functions AND this very manual page were written by Lawrence Stewart <lstewart@FreeBSD.org> โ€” and get this, it was sponsored by Netflix, Inc. ๐Ÿฟ like yes bestie, your streaming service funded your math library, we love a corporate glow-up ๐Ÿ’…โœจ


and that's a wrap on the whole page, bestie!! ๐ŸŽ€ you made it to the bottom, which honestly deserves a little reward ๐Ÿฆ‹ this cutie of a manpage came from Debian and is dated July 4, 2019 โ€” go forth and do math responsibly, mwah ๐Ÿ’–๐ŸŒธ

๐Ÿ“ฆ where this page comes from