Introduce <sys/qmath.h>, a fixed-point math library from Netflix.


This makes it possible to perform mathematical operations
on
fractional values without using floating point. It operates on Q
numbers, which are integer-sized, opaque structures initialized
to hold a chosen number of integer and fractional
bits.


For a general description of the Q number system, see the "Fixed Point
Representation & Fractional Math" whitepaper[1]; for the actual
API see the qmath(3) man page.

This is one of dependencies for the upcoming stats(3) framework[2]
that will be applied to the TCP stack in a later commit.

1. https://www.superkits.net/whitepapers/Fixed%20Point%20Representation%20&%20Fractional%20Math.pdf
2. https://reviews.freebsd.org/D20477

Reviewed by:	bcr (man pages, earlier version), sef (earlier version)
Discussed with:	cem, dteske, imp, lstewart
Sponsored By:	Klara Inc, Netflix
Obtained from:	Netflix
Differential Revision:	https://reviews.freebsd.org/D20116
This commit is contained in:
Edward Tomasz Napierala 2019-08-27 11:46:22 +00:00
parent f69c06c303
commit 5a38af1fb8
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=351544
15 changed files with 3188 additions and 1 deletions

View File

@ -217,6 +217,7 @@ rarely, and then only in very-close-to-halfway cases.
.Xr complex 3 ,
.Xr fenv 3 ,
.Xr ieee 3 ,
.Xr qmath 3 ,
.Xr tgmath 3
.Sh HISTORY
A math library with many of the present functions appeared in

View File

@ -13,6 +13,16 @@ MAN= assert.3 \
makedev.3 \
offsetof.3 \
${PTHREAD_MAN} \
Q_FRAWMASK.3 \
Q_IFRAWMASK.3 \
Q_INI.3 \
Q_IRAWMASK.3 \
Q_QABS.3 \
Q_QADDI.3 \
Q_QADDQ.3 \
Q_SIGNED.3 \
Q_SIGNSHFT.3 \
qmath.3 \
queue.3 \
sigevent.3 \
siginfo.3 \
@ -72,6 +82,68 @@ MLINKS+= fpgetround.3 fpgetmask.3 \
MLINKS+= makedev.3 major.3 \
makedev.3 minor.3
MLINKS+= ${PTHREAD_MLINKS}
MLINKS+= Q_FRAWMASK.3 Q_GFRAW.3 \
Q_FRAWMASK.3 Q_GFABSVAL.3 \
Q_FRAWMASK.3 Q_GFVAL.3 \
Q_FRAWMASK.3 Q_SFVAL.3
MLINKS+= Q_IFRAWMASK.3 Q_IFVALIMASK.3 \
Q_IFRAWMASK.3 Q_IFVALFMASK.3 \
Q_IFRAWMASK.3 Q_GIFRAW.3 \
Q_IFRAWMASK.3 Q_GIFABSVAL.3 \
Q_IFRAWMASK.3 Q_GIFVAL.3 \
Q_IFRAWMASK.3 Q_SIFVAL.3 \
Q_IFRAWMASK.3 Q_SIFVALS.3
MLINKS+= Q_INI.3 Q_NCBITS.3 \
Q_INI.3 Q_BT.3 \
Q_INI.3 Q_TC.3 \
Q_INI.3 Q_NTBITS.3 \
Q_INI.3 Q_NFCBITS.3 \
Q_INI.3 Q_MAXNFBITS.3 \
Q_INI.3 Q_NFBITS.3 \
Q_INI.3 Q_NIBITS.3 \
Q_INI.3 Q_RPSHFT.3 \
Q_INI.3 Q_ABS.3 \
Q_INI.3 Q_MAXSTRLEN.3 \
Q_INI.3 Q_TOSTR.3 \
Q_INI.3 Q_SHL.3 \
Q_INI.3 Q_SHR.3 \
Q_INI.3 Q_DEBUG.3 \
Q_INI.3 Q_DFV2BFV.3
MLINKS+= Q_IRAWMASK.3 Q_GIRAW.3 \
Q_IRAWMASK.3 Q_GIABSVAL.3 \
Q_IRAWMASK.3 Q_GIVAL.3 \
Q_IRAWMASK.3 Q_SIVAL.3
MLINKS+= Q_QABS.3 Q_Q2D.3 \
Q_QABS.3 Q_Q2F.3
MLINKS+= Q_QADDI.3 Q_QDIVI.3 \
Q_QADDI.3 Q_QMULI.3 \
Q_QADDI.3 Q_QSUBI.3 \
Q_QADDI.3 Q_QFRACI.3 \
Q_QADDI.3 Q_QCPYVALI.3
MLINKS+= Q_QADDQ.3 Q_QDIVQ.3 \
Q_QADDQ.3 Q_QMULQ.3 \
Q_QADDQ.3 Q_QSUBQ.3 \
Q_QADDQ.3 Q_NORMPREC.3 \
Q_QADDQ.3 Q_QMAXQ.3 \
Q_QADDQ.3 Q_QMINQ.3 \
Q_QADDQ.3 Q_QCLONEQ.3 \
Q_QADDQ.3 Q_QCPYVALQ.3
MLINKS+= Q_SIGNED.3 Q_LTZ.3 \
Q_SIGNED.3 Q_PRECEQ.3 \
Q_SIGNED.3 Q_QLTQ.3 \
Q_SIGNED.3 Q_QLEQ.3 \
Q_SIGNED.3 Q_QGTQ.3 \
Q_SIGNED.3 Q_QGEQ.3 \
Q_SIGNED.3 Q_QEQ.3 \
Q_SIGNED.3 Q_QNEQ.3 \
Q_SIGNED.3 Q_OFLOW.3 \
Q_SIGNED.3 Q_RELPREC.3
MLINKS+= Q_SIGNSHFT.3 Q_SSIGN.3 \
Q_SIGNSHFT.3 Q_CRAWMASK.3 \
Q_SIGNSHFT.3 Q_SRAWMASK.3 \
Q_SIGNSHFT.3 Q_GCRAW.3 \
Q_SIGNSHFT.3 Q_GCVAL.3 \
Q_SIGNSHFT.3 Q_SCVAL.3
MLINKS+= queue.3 LIST_CLASS_ENTRY.3 \
queue.3 LIST_CLASS_HEAD.3 \
queue.3 LIST_EMPTY.3 \

125
share/man/man3/Q_FRAWMASK.3 Normal file
View File

@ -0,0 +1,125 @@
.\"
.\" 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 Q_FRAWMASK 3
.Os
.Sh NAME
.Nm Q_FRAWMASK ,
.Nm Q_GFRAW ,
.Nm Q_GFABSVAL ,
.Nm Q_GFVAL ,
.Nm Q_SFVAL
.Nd fixed-point math functions which manipulate the fractional data bits
.Sh SYNOPSIS
.In sys/qmath.h
.Ft ITYPE
.Fn Q_FRAWMASK "QTYPE q"
.Ft ITYPE
.Fn Q_GFRAW "QTYPE q"
.Ft ITYPE
.Fn Q_GFABSVAL "QTYPE q"
.Ft ITYPE
.Fn Q_GFVAL "QTYPE q"
.Ft QTYPE
.Fn Q_SFVAL "QTYPE q" "ITYPE fv"
.Sh DESCRIPTION
.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 .
.Pp
All of those functions operate on
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 as
.Fa QTYPE .
The
.Fa ITYPE
refers to the
.Xr stdint 7
integer types.
.Pp
For more details, see
.Xr qmath 3 .
.Sh RETURN VALUES
.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.
.Sh SEE ALSO
.Xr errno 2 ,
.Xr qmath 3 ,
.Xr stdint 7
.Sh HISTORY
The
.Xr qmath 3
functions first appeared in
.Fx 13.0 .
.Sh AUTHORS
.An -nosplit
The
.Xr qmath 3
functions and this manual page were written by
.An Lawrence Stewart Aq Mt lstewart@FreeBSD.org
and sponsored by Netflix, Inc.

View File

@ -0,0 +1,162 @@
.\"
.\" 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 Q_IFRAWMASK 3
.Os
.Sh NAME
.Nm Q_IFRAWMASK ,
.Nm Q_IFVALIMASK ,
.Nm Q_IFVALFMASK ,
.Nm Q_GIFRAW ,
.Nm Q_GIFABSVAL ,
.Nm Q_GIFVAL ,
.Nm Q_SIFVAL ,
.Nm Q_SIFVALS
.Nd fixed-point math functions which manipulate the combined integer/fractional
data bits
.Sh SYNOPSIS
.In sys/qmath.h
.Ft ITYPE
.Fn Q_IFRAWMASK "QTYPE q"
.Ft ITYPE
.Fn Q_IFVALIMASK "QTYPE q"
.Ft ITYPE
.Fn Q_IFVALFMASK "QTYPE q"
.Ft ITYPE
.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"
.Sh DESCRIPTION
.Fn Q_IFRAWMASK
returns a
.Fa q Ns -specific
bit mask for
.Fa q Ap s
combined integer and fractional data bits.
.Pp
.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 .
.Pp
All of those functions operate on
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 as
.Fa QTYPE .
The
.Fa ITYPE
refers to the
.Xr stdint 7
integer types.
.Pp
For more details, see
.Xr qmath 3 .
.Sh RETURN VALUES
.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.
.Sh SEE ALSO
.Xr errno 2 ,
.Xr qmath 3 ,
.Xr stdint 7
.Sh HISTORY
The
.Xr qmath 3
functions first appeared in
.Fx 13.0 .
.Sh AUTHORS
.An -nosplit
The
.Xr qmath 3
functions and this manual page were written by
.An Lawrence Stewart Aq Mt lstewart@FreeBSD.org
and sponsored by Netflix, Inc.

261
share/man/man3/Q_INI.3 Normal file
View File

@ -0,0 +1,261 @@
.\"
.\" 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 Q_INI 3
.Os
.Sh NAME
.Nm Q_INI ,
.Nm Q_NCBITS ,
.Nm Q_BT ,
.Nm Q_TC ,
.Nm Q_NTBITS ,
.Nm Q_NFCBITS ,
.Nm Q_MAXNFBITS ,
.Nm Q_NFBITS ,
.Nm Q_NIBITS ,
.Nm Q_RPSHFT ,
.Nm Q_ABS ,
.Nm Q_MAXSTRLEN ,
.Nm Q_TOSTR ,
.Nm Q_SHL ,
.Nm Q_SHR ,
.Nm Q_DEBUG
.Nd fixed-point math miscellaneous functions/variables
.Sh SYNOPSIS
.In sys/qmath.h
.Ft QTYPE
.Fn Q_INI "QTYPE *q" "ITYPE iv" "ITYPE dfv" "int rpshft"
.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"
.Ft ITYPE
.Fn Q_DFV2BFV "ITYPE dfv" "int nfbits"
.Sh DESCRIPTION
.Fn Q_INI
initialises a Q number with the supplied integral value
.Fa iv
and decimal fractional value
.Fa dfv ,
with appropriate control bits based on the requested radix shift point
.Fa rpshft .
.Fa dfv
must be passed as a preprocessor literal to preserve leading zeroes.
.Pp
The
.Dv Q_NCBITS
defined constant specifies the number of reserved control bits, currently 3.
.Pp
.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.
.Pp
.Fn Q_DFV2BFV
converts decimal fractional value
.Fa dfv
to its binary-encoded representation with
.Fa nfbits
of binary precision.
.Fa dfv
must be passed as a preprocessor literal to preserve leading zeroes.
The returned value can be used to set a Q number's fractional bits, for example
using
.Fn Q_SFVAL .
.Pp
All of those functions operate on
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 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
For more details, see
.Xr qmath 3 .
.Sh RETURN VALUES
.Fn Q_INI
returns the initialised Q number which can be used to chain initialise
additional Q numbers.
.Pp
.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.
.Pp
.Fn Q_DFV2BFV
returns the binary-encoded representation of decimal fractional value
.Fa dfv
with
.Fa nfbits
of binary precision.
.Sh SEE ALSO
.Xr errno 2 ,
.Xr qmath 3 ,
.Xr stdint 7
.Sh HISTORY
The
.Xr qmath 3
functions first appeared in
.Fx 13.0 .
.Sh AUTHORS
.An -nosplit
The
.Xr qmath 3
functions and this manual page were written by
.An Lawrence Stewart Aq Mt lstewart@FreeBSD.org
and sponsored by Netflix, Inc.

125
share/man/man3/Q_IRAWMASK.3 Normal file
View File

@ -0,0 +1,125 @@
.\"
.\" 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 Q_IRAWMASK 3
.Os
.Sh NAME
.Nm Q_IRAWMASK ,
.Nm Q_GIRAW ,
.Nm Q_GIABSVAL ,
.Nm Q_GIVAL ,
.Nm Q_SIVAL
.Nd fixed-point math functions which manipulate the integer data bits
.Sh SYNOPSIS
.In sys/qmath.h
.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"
.Sh DESCRIPTION
.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 .
.Pp
All of those functions operate on
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 as
.Fa QTYPE .
The
.Fa ITYPE
refers to the
.Xr stdint 7
integer types.
.Pp
For more details, see
.Xr qmath 3 .
.Sh RETURN VALUES
.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.
.Sh SEE ALSO
.Xr errno 2 ,
.Xr qmath 3 ,
.Xr stdint 7
.Sh HISTORY
The
.Xr qmath 3
functions first appeared in
.Fx 13.0 .
.Sh AUTHORS
.An -nosplit
The
.Xr qmath 3
functions and this manual page were written by
.An Lawrence Stewart Aq Mt lstewart@FreeBSD.org
and sponsored by Netflix, Inc.

101
share/man/man3/Q_QABS.3 Normal file
View File

@ -0,0 +1,101 @@
.\"
.\" 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 Q_QABS 3
.Os
.Sh NAME
.Nm Q_QABS ,
.Nm Q_Q2S ,
.Nm Q_Q2F
.Nd fixed-point math functions which operate on a single Q number
.Sh SYNOPSIS
.In sys/qmath.h
.Ft QTYPE
.Fn Q_QABS "QTYPE q"
.Ft double
.Fn Q_Q2D "QTYPE q"
.Ft float
.Fn Q_Q2F "QTYPE q"
.Sh DESCRIPTION
The
.Fn Q_QABS
function returns an absolute value representation of
.Fa q .
.Pp
The
.Fn Q_Q2D
and
.Fn Q_Q2F
functions return the double and float representations of
.Fa q
respectively.
.Pp
All of those functions operate on
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 as
.Fa QTYPE .
.Pp
For more details, see
.Xr qmath 3 .
.Sh RETURN VALUES
.Fn Q_QABS
function returns a QTYPE that is identical to that of
.Fa q .
.Pp
The
.Fn Q_Q2D
and
.Fn Q_Q2F
functions return the double and float representations of
.Fa q
respectively.
.Sh SEE ALSO
.Xr errno 2 ,
.Xr qmath 3 ,
.Xr stdint 7
.Sh HISTORY
The
.Xr qmath 3
functions first appeared in
.Fx 13.0 .
.Sh AUTHORS
.An -nosplit
The
.Xr qmath 3
functions and this manual page were written by
.An Lawrence Stewart Aq Mt lstewart@FreeBSD.org
and sponsored by Netflix, Inc.

134
share/man/man3/Q_QADDI.3 Normal file
View File

@ -0,0 +1,134 @@
.\"
.\" 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 Q_QADDI 3
.Os
.Sh NAME
.Nm Q_QADDI ,
.Nm Q_QDIVI ,
.Nm Q_QMULI ,
.Nm Q_QSUBI ,
.Nm Q_QFRACI ,
.Nm Q_QCPYVALI
.Nd fixed-point math functions which apply integers to a Q number
.Sh SYNOPSIS
.In sys/qmath.h
.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"
.Sh DESCRIPTION
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 .
.Pp
All of those functions operate on
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 as
.Fa QTYPE .
The
.Fa ITYPE
refers to the
.Xr stdint 7
integer types.
.Pp
For more details, see
.Xr qmath 3 .
.Sh RETURN VALUES
.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.
.Sh SEE ALSO
.Xr errno 2 ,
.Xr qmath 3 ,
.Xr stdint 7
.Sh HISTORY
The
.Xr qmath 3
functions first appeared in
.Fx 13.0 .
.Sh AUTHORS
.An -nosplit
The
.Xr qmath 3
functions and this manual page were written by
.An Lawrence Stewart Aq Mt lstewart@FreeBSD.org
and sponsored by Netflix, Inc.

175
share/man/man3/Q_QADDQ.3 Normal file
View File

@ -0,0 +1,175 @@
.\"
.\" 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 Q_QADDQ 3
.Os
.Sh NAME
.Nm Q_QADDQ ,
.Nm Q_QDIVQ ,
.Nm Q_QMULQ ,
.Nm Q_QSUBQ ,
.Nm Q_NORMPREC ,
.Nm Q_QMAXQ ,
.Nm Q_QMINQ ,
.Nm Q_QCLONEQ ,
.Nm Q_CPYVALQ
.Nd fixed-point math functions which operate on two Q numbers
.Sh SYNOPSIS
.In sys/qmath.h
.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
.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"
.Sh DESCRIPTION
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 .
Both arguments must be initialized with the same fractional radix point.
.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.
.Pp
All of those functions operate on 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 as
.Fa QTYPE .
.Pp
For more details, see
.Xr qmath 3 .
.Sh RETURN VALUES
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.
.Er ERANGE is also returned when the precision of arguments
does not match.
.Pp
The
.Fn Q_QMAXQ
and
.Fn Q_QMINQ
functions return the numerically larger or smaller of their two inputs
respectively.
.Sh SEE ALSO
.Xr errno 2 ,
.Xr qmath 3 ,
.Xr stdint 7
.Sh HISTORY
The
.Xr qmath 3
functions first appeared in
.Fx 13.0 .
.Sh AUTHORS
.An -nosplit
The
.Xr qmath 3
functions and this manual page were written by
.An Lawrence Stewart Aq Mt lstewart@FreeBSD.org
and sponsored by Netflix, Inc.

210
share/man/man3/Q_SIGNED.3 Normal file
View File

@ -0,0 +1,210 @@
.\"
.\" 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 Q_SIGNED 3
.Os
.Sh NAME
.Nm Q_SIGNED ,
.Nm Q_LTZ ,
.Nm Q_PRECEQ ,
.Nm Q_QLTQ ,
.Nm Q_QLEQ ,
.Nm Q_QGTQ ,
.Nm Q_QGEQ ,
.Nm Q_QEQ ,
.Nm Q_QNEQ ,
.Nm Q_OFLOW ,
.Nm Q_RELPREC
.Nd fixed-point math comparison and logic functions
.Sh SYNOPSIS
.In sys/qmath.h
.Ft bool
.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"
.Sh DESCRIPTION
.Fn Q_SIGNED
returns
.Ft true
if the numeric data type passed in as
.Fa n
is signed, or
.Ft false
otherwise.
.Pp
.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 .
.Pp
All of those functions operate on
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 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
For more details, see
.Xr qmath 3 .
.Sh RETURN VALUES
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.
.Sh SEE ALSO
.Xr errno 2 ,
.Xr qmath 3 ,
.Xr stdint 7
.Sh HISTORY
The
.Xr qmath 3
functions first appeared in
.Fx 13.0 .
.Sh AUTHORS
.An -nosplit
The
.Xr qmath 3
functions and this manual page were written by
.An Lawrence Stewart Aq Mt lstewart@FreeBSD.org
and sponsored by Netflix, Inc.

147
share/man/man3/Q_SIGNSHFT.3 Normal file
View File

@ -0,0 +1,147 @@
.\"
.\" 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 Q_SIGNSHFT 3
.Os
.Sh NAME
.Nm Q_SIGNSHFT ,
.Nm Q_SSIGN ,
.Nm Q_CRAWMASK ,
.Nm Q_SRAWMASK ,
.Nm Q_GCRAW ,
.Nm Q_GCVAL ,
.Nm Q_SCVAL
.Nd fixed-point math functions which manipulate the control/sign data bits
.Sh SYNOPSIS
.In sys/qmath.h
.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"
.Sh DESCRIPTION
.Fn Q_SIGNSHFT
gets the bit position of
.Fa q Ap s
sign bit relative to bit zero.
.Pp
.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
.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.
.Pp
.Fn Q_SCVAL
sets
.Fa q Ap s
control bits to the value
.Fa cv .
.Pp
All of those functions operate on
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 as
.Fa QTYPE .
The
.Fa ITYPE
refers to the
.Xr stdint 7
integer types.
.Pp
For more details, see
.Xr qmath 3 .
.Sh RETURN VALUES
.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.
.Sh SEE ALSO
.Xr errno 2 ,
.Xr qmath 3 ,
.Xr stdint 7
.Sh HISTORY
The
.Xr qmath 3
functions first appeared in
.Fx 13.0 .
.Sh AUTHORS
.An -nosplit
The
.Xr qmath 3
functions and this manual page were written by
.An Lawrence Stewart Aq Mt lstewart@FreeBSD.org
and sponsored by Netflix, Inc.

389
share/man/man3/qmath.3 Normal file
View File

@ -0,0 +1,389 @@
.\"
.\" 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 4, 2019
.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
.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
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.
.Pp
For more details, see the
.Sx IMPLEMENTATION DETAILS
below.
.Sh LIST OF FUNCTIONS
.de Cl
.Bl -column "isgreaterequal" "bessel function of the second kind of the order 0"
.Em "Name Description"
..
.Ss Functions which create/initialise a Q number
.Cl
.Xr Q_INI 3 initialise a Q number
.El
.Ss Numeric functions which operate on two Q numbers
.Cl
.Xr Q_QADDQ 3 addition
.Xr Q_QDIVQ 3 division
.Xr Q_QMULQ 3 multiplication
.Xr Q_QSUBQ 3 subtraction
.Xr Q_NORMPREC 3 normalisation
.Xr Q_QMAXQ 3 maximum function
.Xr Q_QMINQ 3 minimum function
.Xr Q_QCLONEQ 3 identical copy
.Xr Q_QCPYVALQ 3 representational copy
.El
.Ss Numeric functions which apply integers to a Q number
.Cl
.Xr Q_QADDI 3 addition
.Xr Q_QDIVI 3 division
.Xr Q_QMULI 3 multiplication
.Xr Q_QSUBI 3 subtraction
.Xr Q_QFRACI 3 fraction
.Xr Q_QCPYVALI 3 overwrite
.El
.Ss Numeric functions which operate on a single Q number
.Cl
.Xr Q_QABS 3 absolute value
.Xr Q_Q2D 3 double representation
.Xr Q_Q2F 3 float representation
.El
.Ss Comparison and logic functions
.Cl
.Xr Q_SIGNED 3 determine sign
.Xr Q_LTZ 3 less than zero
.Xr Q_PRECEQ 3 compare bits
.Xr Q_QLTQ 3 less than
.Xr Q_QLEQ 3 less or equal
.Xr Q_QGTQ 3 greater than
.Xr Q_QGEQ 3 greater or equal
.Xr Q_QEQ 3 equal
.Xr Q_QNEQ 3 not equal
.Xr Q_OFLOW 3 would overflow
.Xr Q_RELPREC 3 relative precision
.El
.Ss Functions which manipulate the control/sign data bits
.Cl
.Xr Q_SIGNSHFT 3 sign bit position
.Xr Q_SSIGN 3 sign bit
.Xr Q_CRAWMASK 3 control bitmask
.Xr Q_SRAWMASK 3 sign bitmask
.Xr Q_GCRAW 3 raw control bits
.Xr Q_GCVAL 3 value of control bits
.Xr Q_SCVAL 3 set control bits
.El
.Ss Functions which manipulate the combined integer/fractional data bits
.Cl
.Xr Q_IFRAWMASK 3 integer/fractional bitmask
.Xr Q_IFVALIMASK 3 value of integer bits
.Xr Q_IFVALFMASK 3 value of fractional bits
.Xr Q_GIFRAW 3 raw integer/fractional bits
.Xr Q_GIFABSVAL 3 absolute value of fractional bits
.Xr Q_GIFVAL 3 real value of fractional bits
.Xr Q_SIFVAL 3 set integer/fractional bits
.Xr Q_SIFVALS 3 set separate integer/fractional values
.El
.Ss Functions which manipulate the integer data bits
.Cl
.Xr Q_IRAWMASK 3 integer bitmask
.Xr Q_GIRAW 3 raw integer bits
.Xr Q_GIABSVAL 3 absolute value of integer bits
.Xr Q_GIVAL 3 real value of integer bits
.Xr Q_SIVAL 3 set integer bits
.El
.Ss Functions which manipulate the fractional data bits
.Cl
.Xr Q_FRAWMASK 3 fractional bitmask
.Xr Q_GFRAW 3 raw fractional bits
.Xr Q_GFABSVAL 3 absolute value of fractional bits
.Xr Q_GFVAL 3 real value of fractional bits
.Xr Q_SFVAL 3 set fractional bits
.El
.Ss Miscellaneous functions/variables
.Cl
.Xr Q_NCBITS 3 number of reserved control bits
.Xr Q_BT 3 C data type
.Xr Q_TC 3 casted data type
.Xr Q_NTBITS 3 number of total bits
.Xr Q_NFCBITS 3 number of control-encoded fractional bits
.Xr Q_MAXNFBITS 3 number of maximum fractional bits
.Xr Q_NFBITS 3 number of effective fractional bits
.Xr Q_NIBITS 3 number of integer bits
.Xr Q_RPSHFT 3 bit position of radix point
.Xr Q_ABS 3 absolute value
.Xr Q_MAXSTRLEN 3 number of characters to render string
.Xr Q_TOSTR 3 render string
.Xr Q_SHL 3 left-shifted value
.Xr Q_SHR 3 right-shifted value
.Xr Q_DEBUG 3 render debugging information
.Xr Q_DFV2BFV 3 convert decimal fractional value
.El
.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 EXAMPLES
.Ss Calculating area of a circle with r=4.2 and rpshft=16
.Bd -literal -offset indent
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);
.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, 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);
.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 Q_FRAWMASK 3 ,
.Xr Q_IFRAWMASK 3 ,
.Xr Q_INI 3 ,
.Xr Q_IRAWMASK 3 ,
.Xr Q_QABS 3 ,
.Xr Q_QADDI 3 ,
.Xr Q_QADDQ 3 ,
.Xr Q_SIGNED 3 ,
.Xr Q_SIGNSHFT 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.

632
sys/sys/qmath.h Normal file
View File

@ -0,0 +1,632 @@
/*-
* 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.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 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$
*/
/*
* Data types and APIs for fixed-point math based on the "Q" number format.
*
* Author: Lawrence Stewart <lstewart@netflix.com>
*
* The 3 LSBs of all base data types are reserved for embedded control data:
* bits 1-2 specify the radix point shift index i.e. 00,01,10,11 == 1,2,3,4
* bit 3 specifies the radix point shift index 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 depends on the underlying storage type chosen.
*/
#ifndef _SYS_QMATH_H_
#define _SYS_QMATH_H_
#include <machine/_stdint.h>
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;
/* typedef int128_t s128q_t; Not yet */
/* typedef uint128_t u128q_t; Not yet */
typedef s64q_t smaxq_t;
typedef u64q_t umaxq_t;
/* The underlying base type of 'q'. */
#define Q_BT(q) __typeof(q)
/* Type-cast variable 'v' to the same underlying type as 'q'. */
#define Q_TC(q, v) ((Q_BT(q))(v))
/* Number of total bits associated with the data type underlying 'q'. */
#define Q_NTBITS(q) ((uint32_t)(sizeof(q) << 3))
/* Number of LSBs reserved for control data. */
#define Q_NCBITS ((uint32_t)3)
/* Number of control-encoded bits reserved for fractional component data. */
#define Q_NFCBITS(q) \
((uint32_t)(((Q_GCRAW(q) & 0x3) + 1) << ((Q_GCRAW(q) & 0x4) ? 4 : 1)))
/* Min/max number of bits that can be reserved for fractional component data. */
#define Q_MINNFBITS(q) ((uint32_t)(2))
#define Q_MAXNFBITS(q) ((uint32_t)(Q_NTBITS(q) - Q_SIGNED(q) - Q_NCBITS))
/*
* Number of bits actually reserved for fractional component data. This can be
* less than the value returned by Q_NFCBITS() as we treat any excess
* control-encoded number of bits for the underlying data type as meaning all
* available bits are reserved for fractional component data i.e. zero int bits.
*/
#define Q_NFBITS(q) \
(Q_NFCBITS(q) > Q_MAXNFBITS(q) ? Q_MAXNFBITS(q) : Q_NFCBITS(q))
/* Number of bits available for integer component data. */
#define Q_NIBITS(q) ((uint32_t)(Q_NTBITS(q) - Q_RPSHFT(q) - Q_SIGNED(q)))
/* The radix point offset relative to the LSB. */
#define Q_RPSHFT(q) (Q_NCBITS + Q_NFBITS(q))
/* The sign bit offset relative to the LSB. */
#define Q_SIGNSHFT(q) (Q_NTBITS(q) - 1)
/* Set the sign bit to 0 ('isneg' is F) or 1 ('isneg' is T). */
#define Q_SSIGN(q, isneg) \
((q) = ((Q_SIGNED(q) && (isneg)) ? (q) | (1ULL << Q_SIGNSHFT(q)) : \
(q) & ~(1ULL << Q_SIGNSHFT(q))))
/* Manipulate the 'q' bits holding control/sign data. */
#define Q_CRAWMASK(q) 0x7ULL
#define Q_SRAWMASK(q) (1ULL << Q_SIGNSHFT(q))
#define Q_GCRAW(q) ((q) & Q_CRAWMASK(q))
#define Q_GCVAL(q) Q_GCRAW(q)
#define Q_SCVAL(q, cv) ((q) = ((q) & ~Q_CRAWMASK(q)) | (cv))
/* Manipulate the 'q' bits holding combined integer/fractional data. */
#define Q_IFRAWMASK(q) \
Q_TC(q, Q_SIGNED(q) ? ~(Q_SRAWMASK(q) | Q_CRAWMASK(q)) : ~Q_CRAWMASK(q))
#define Q_IFMAXVAL(q) Q_TC(q, Q_IFRAWMASK(q) >> Q_NCBITS)
#define Q_IFMINVAL(q) Q_TC(q, Q_SIGNED(q) ? -Q_IFMAXVAL(q) : 0)
#define Q_IFVALIMASK(q) Q_TC(q, ~Q_IFVALFMASK(q))
#define Q_IFVALFMASK(q) Q_TC(q, (1ULL << Q_NFBITS(q)) - 1)
#define Q_GIFRAW(q) Q_TC(q, (q) & Q_IFRAWMASK(q))
#define Q_GIFABSVAL(q) Q_TC(q, Q_GIFRAW(q) >> Q_NCBITS)
#define Q_GIFVAL(q) Q_TC(q, Q_LTZ(q) ? -Q_GIFABSVAL(q) : Q_GIFABSVAL(q))
#define Q_SIFVAL(q, ifv) \
((q) = ((q) & (~(Q_SRAWMASK(q) | Q_IFRAWMASK(q)))) | \
(Q_TC(q, Q_ABS(ifv)) << Q_NCBITS) | \
(Q_LTZ(ifv) ? 1ULL << Q_SIGNSHFT(q) : 0))
#define Q_SIFVALS(q, iv, fv) \
((q) = ((q) & (~(Q_SRAWMASK(q) | Q_IFRAWMASK(q)))) | \
(Q_TC(q, Q_ABS(iv)) << Q_RPSHFT(q)) | \
(Q_TC(q, Q_ABS(fv)) << Q_NCBITS) | \
(Q_LTZ(iv) || Q_LTZ(fv) ? 1ULL << Q_SIGNSHFT(q) : 0))
/* Manipulate the 'q' bits holding integer data. */
#define Q_IRAWMASK(q) Q_TC(q, Q_IFRAWMASK(q) & ~Q_FRAWMASK(q))
#define Q_IMAXVAL(q) Q_TC(q, Q_IRAWMASK(q) >> Q_RPSHFT(q))
#define Q_IMINVAL(q) Q_TC(q, Q_SIGNED(q) ? -Q_IMAXVAL(q) : 0)
#define Q_GIRAW(q) Q_TC(q, (q) & Q_IRAWMASK(q))
#define Q_GIABSVAL(q) Q_TC(q, Q_GIRAW(q) >> Q_RPSHFT(q))
#define Q_GIVAL(q) Q_TC(q, Q_LTZ(q) ? -Q_GIABSVAL(q) : Q_GIABSVAL(q))
#define Q_SIVAL(q, iv) \
((q) = ((q) & ~(Q_SRAWMASK(q) | Q_IRAWMASK(q))) | \
(Q_TC(q, Q_ABS(iv)) << Q_RPSHFT(q)) | \
(Q_LTZ(iv) ? 1ULL << Q_SIGNSHFT(q) : 0))
/* Manipulate the 'q' bits holding fractional data. */
#define Q_FRAWMASK(q) Q_TC(q, ((1ULL << Q_NFBITS(q)) - 1) << Q_NCBITS)
#define Q_FMAXVAL(q) Q_TC(q, Q_FRAWMASK(q) >> Q_NCBITS)
#define Q_GFRAW(q) Q_TC(q, (q) & Q_FRAWMASK(q))
#define Q_GFABSVAL(q) Q_TC(q, Q_GFRAW(q) >> Q_NCBITS)
#define Q_GFVAL(q) Q_TC(q, Q_LTZ(q) ? -Q_GFABSVAL(q) : Q_GFABSVAL(q))
#define Q_SFVAL(q, fv) \
((q) = ((q) & ~(Q_SRAWMASK(q) | Q_FRAWMASK(q))) | \
(Q_TC(q, Q_ABS(fv)) << Q_NCBITS) | \
(Q_LTZ(fv) ? 1ULL << Q_SIGNSHFT(q) : 0))
/*
* Calculate the number of bits required per 'base' digit, rounding up or down
* for non power-of-two bases.
*/
#define Q_BITSPERBASEDOWN(base) (flsll(base) - 1)
#define Q_BITSPERBASEUP(base) (flsll(base) - (__builtin_popcountll(base) == 1))
#define Q_BITSPERBASE(base, rnd) Q_BITSPERBASE##rnd(base)
/*
* Upper bound number of digits required to render 'nbits' worth of integer
* component bits with numeric base 'base'. Overestimates for power-of-two
* bases.
*/
#define Q_NIBITS2NCHARS(nbits, base) \
({ \
int _bitsperbase = Q_BITSPERBASE(base, DOWN); \
(((nbits) + _bitsperbase - 1) / _bitsperbase); \
})
#define Q_NFBITS2NCHARS(nbits, base) (nbits)
/*
* Maximum number of chars required to render 'q' as a C-string of base 'base'.
* Includes space for sign, radix point and NUL-terminator.
*/
#define Q_MAXSTRLEN(q, base) \
(2 + Q_NIBITS2NCHARS(Q_NIBITS(q), base) + \
Q_NFBITS2NCHARS(Q_NFBITS(q), base) + Q_SIGNED(q))
/* Yield the next char from integer bits. */
#define Q_IBITS2CH(q, bits, base) \
({ \
__typeof(bits) _tmp = (bits) / (base); \
int _idx = (bits) - (_tmp * (base)); \
(bits) = _tmp; \
"0123456789abcdef"[_idx]; \
})
/* Yield the next char from fractional bits. */
#define Q_FBITS2CH(q, bits, base) \
({ \
int _carry = 0, _idx, _nfbits = Q_NFBITS(q), _shift = 0; \
/* \
* Normalise enough MSBs to yield the next digit, multiply by the \
* base, and truncate residual fractional bits post multiplication. \
*/ \
if (_nfbits > Q_BITSPERBASEUP(base)) { \
/* Break multiplication into two steps to ensure no overflow. */\
_shift = _nfbits >> 1; \
_carry = (((bits) & ((1ULL << _shift) - 1)) * (base)) >> _shift;\
} \
_idx = ((((bits) >> _shift) * (base)) + _carry) >> (_nfbits - _shift);\
(bits) *= (base); /* With _idx computed, no overflow concern. */ \
(bits) &= (1ULL << _nfbits) - 1; /* Exclude residual int bits. */ \
"0123456789abcdef"[_idx]; \
})
/*
* Render the C-string representation of 'q' into 's'. Returns a pointer to the
* final '\0' to allow for easy calculation of the rendered length and easy
* appending to the C-string.
*/
#define Q_TOSTR(q, prec, base, s, slen) \
({ \
char *_r, *_s = s; \
int _i; \
if (Q_LTZ(q) && ((ptrdiff_t)(slen)) > 0) \
*_s++ = '-'; \
Q_BT(q) _part = Q_GIABSVAL(q); \
_r = _s; \
do { \
/* Render integer chars in reverse order. */ \
if ((_s - (s)) < ((ptrdiff_t)(slen))) \
*_s++ = Q_IBITS2CH(q, _part, base); \
else \
_r = NULL; \
} while (_part > 0 && _r != NULL); \
if (!((_s - (s)) < ((ptrdiff_t)(slen)))) \
_r = NULL; \
_i = (_s - _r) >> 1; /* N digits requires int(N/2) swaps. */ \
while (_i-- > 0 && _r != NULL) { \
/* Work from middle out to reverse integer chars. */ \
*_s = *(_r + _i); /* Stash LHS char temporarily. */ \
*(_r + _i) = *(_s - _i - 1); /* Copy RHS char to LHS. */\
*(_s - _i - 1) = *_s; /* Copy LHS char to RHS. */ \
} \
_i = (prec); \
if (_i != 0 && _r != NULL) { \
if ((_s - (s)) < ((ptrdiff_t)(slen))) \
*_s++ = '.'; \
else \
_r = NULL; \
_part = Q_GFABSVAL(q); \
if (_i < 0 || _i > (int)Q_NFBITS(q)) \
_i = Q_NFBITS(q); \
while (_i-- > 0 && _r != NULL) { \
/* Render fraction chars in correct order. */ \
if ((_s - (s)) < ((ptrdiff_t)(slen))) \
*_s++ = Q_FBITS2CH(q, _part, base); \
else \
_r = NULL; \
} \
} \
if ((_s - (s)) < ((ptrdiff_t)(slen)) && _r != NULL) \
*_s = '\0'; \
else { \
_r = NULL; \
if (((ptrdiff_t)(slen)) > 0) \
*(s) = '\0'; \
} \
/* Return a pointer to the '\0' or NULL on overflow. */ \
(_r != NULL ? _s : _r); \
})
/* Left shift an integral value to align with the int bits of 'q'. */
#define Q_SHL(q, iv) \
(Q_LTZ(iv) ? -(Q_ABS(iv) << Q_NFBITS(q)) : \
Q_TC(q, iv) << Q_NFBITS(q))
/* Calculate the relative fractional precision between 'a' and 'b' in bits. */
#define Q_RELPREC(a, b) ((int)Q_NFBITS(a) - (int)Q_NFBITS(b))
/*
* Determine control bits for the desired 'rpshft' radix point shift. Rounds up
* to the nearest valid shift supported by the encoding scheme.
*/
#define Q_CTRLINI(rpshft) \
(((rpshft) <= 8) ? (((rpshft) - 1) >> 1) : (0x4 | (((rpshft) - 1) >> 4)))
/*
* Convert decimal fractional value 'dfv' to its binary-encoded representation
* with 'nfbits' of binary precision. 'dfv' must be passed as a preprocessor
* literal to preserve leading zeroes. The returned result can be used to set a
* Q number's fractional bits e.g. using Q_SFVAL().
*/
#define Q_DFV2BFV(dfv, nfbits) \
({ \
uint64_t _bfv = 0, _thresh = 5, _tmp = dfv; \
int _i = sizeof(""#dfv) - 1; \
/* \
* Compute decimal threshold to determine which \
* conversion rounds will yield a binary 1. \
*/ \
while (--_i > 0) {_thresh *= 10;} \
_i = (nfbits) - 1; \
while (_i >= 0) { \
if (_thresh <= _tmp) { \
_bfv |= 1ULL << _i; \
_tmp = _tmp - _thresh; \
} \
_i--; _tmp <<= 1; \
} \
_bfv; \
})
/*
* Initialise 'q' with raw integer value 'iv', decimal fractional value 'dfv',
* and radix point shift 'rpshft'. Must be done in two steps in case 'iv'
* depends on control bits being set e.g. when passing Q_INTMAX(q) as 'iv'.
*/
#define Q_INI(q, iv, dfv, rpshft) \
({ \
(*(q)) = Q_CTRLINI(rpshft); \
Q_SIFVALS(*(q), iv, Q_DFV2BFV(dfv, Q_NFBITS(*(q)))); \
})
/* Test if 'a' and 'b' fractional precision is the same (T) or not (F). */
#define Q_PRECEQ(a, b) (Q_NFBITS(a) == Q_NFBITS(b))
/* Test if 'n' is a signed type (T) or not (F). Works with any numeric type. */
#define Q_SIGNED(n) (Q_TC(n, -1) < 0)
/*
* Test if 'n' is negative. Works with any numeric type that uses the MSB as the
* sign bit, and also works with Q numbers.
*/
#define Q_LTZ(n) (Q_SIGNED(n) && ((n) & Q_SRAWMASK(n)))
/*
* Return absolute value of 'n'. Works with any standard numeric type that uses
* the MSB as the sign bit, and is signed/unsigned type safe.
* Does not work with Q numbers; use Q_QABS() instead.
*/
#define Q_ABS(n) (Q_LTZ(n) ? -(n) : (n))
/*
* Return an absolute value interpretation of 'q'.
*/
#define Q_QABS(q) (Q_SIGNED(q) ? (q) & ~Q_SRAWMASK(q) : (q))
/* Convert 'q' to float or double representation. */
#define Q_Q2F(q) ((float)Q_GIFVAL(q) / (float)(1ULL << Q_NFBITS(q)))
#define Q_Q2D(q) ((double)Q_GIFVAL(q) / (double)(1ULL << Q_NFBITS(q)))
/* Numerically compare 'a' and 'b' as whole numbers using provided operators. */
#define Q_QCMPQ(a, b, intcmp, fraccmp) \
((Q_GIVAL(a) intcmp Q_GIVAL(b)) || \
((Q_GIVAL(a) == Q_GIVAL(b)) && (Q_GFVAL(a) fraccmp Q_GFVAL(b))))
/* Test if 'a' is numerically less than 'b' (T) or not (F). */
#define Q_QLTQ(a, b) Q_QCMPQ(a, b, <, <)
/* Test if 'a' is numerically less than or equal to 'b' (T) or not (F). */
#define Q_QLEQ(a, b) Q_QCMPQ(a, b, <, <=)
/* Test if 'a' is numerically greater than 'b' (T) or not (F). */
#define Q_QGTQ(a, b) Q_QCMPQ(a, b, >, >)
/* Test if 'a' is numerically greater than or equal to 'b' (T) or not (F). */
#define Q_QGEQ(a, b) Q_QCMPQ(a, b, >, >=)
/* Test if 'a' is numerically equal to 'b' (T) or not (F). */
#define Q_QEQ(a, b) Q_QCMPQ(a, b, ==, ==)
/* Test if 'a' is numerically not equal to 'b' (T) or not (F). */
#define Q_QNEQ(a, b) Q_QCMPQ(a, b, !=, !=)
/* Returns the numerically larger of 'a' and 'b'. */
#define Q_QMAXQ(a, b) (Q_GT(a, b) ? (a) : (b))
/* Returns the numerically smaller of 'a' and 'b'. */
#define Q_QMINQ(a, b) (Q_LT(a, b) ? (a) : (b))
/*
* Test if 'a' can be represented by 'b' with full accuracy (T) or not (F).
* The type casting has to be done to a's type so that any truncation caused by
* the casts will not affect the logic.
*/
#define Q_QCANREPQ(a, b) \
((((Q_LTZ(a) && Q_SIGNED(b)) || !Q_LTZ(a)) && \
Q_GIABSVAL(a) <= Q_TC(a, Q_IMAXVAL(b)) && \
Q_GFABSVAL(a) <= Q_TC(a, Q_FMAXVAL(b))) ? \
0 : EOVERFLOW)
/* Test if raw integer value 'i' can be represented by 'q' (T) or not (F). */
#define Q_QCANREPI(q, i) \
((((Q_LTZ(i) && Q_SIGNED(q)) || !Q_LTZ(i)) && \
Q_ABS(i) <= Q_TC(i, Q_IMAXVAL(q))) ? 0 : EOVERFLOW)
/*
* Returns a Q variable debug format string with appropriate modifiers and
* padding relevant to the underlying Q data type.
*/
#define Q_DEBUGFMT_(prefmt, postfmt, mod, hexpad) \
prefmt \
/* Var name + address. */ \
"\"%s\"@%p" \
/* Data type. */ \
"\n\ttype=%c%dq_t, " \
/* Qm.n notation; 'm' = # int bits, 'n' = # frac bits. */ \
"Qm.n=Q%d.%d, " \
/* Radix point shift relative to the underlying data type's LSB. */ \
"rpshft=%d, " \
/* Min/max integer values which can be represented. */ \
"imin=0x%0" #mod "x, " \
"imax=0x%0" #mod "x" \
/* Raw hex dump of all bits. */ \
"\n\tqraw=0x%0" #hexpad #mod "x" \
/* Bit masks for int/frac/ctrl bits. */ \
"\n\timask=0x%0" #hexpad #mod "x, " \
"fmask=0x%0" #hexpad #mod "x, " \
"cmask=0x%0" #hexpad #mod "x, " \
"ifmask=0x%0" #hexpad #mod "x" \
/* Hex dump of masked int bits; 'iraw' includes shift */ \
"\n\tiraw=0x%0" #hexpad #mod "x, " \
"iabsval=0x%" #mod "x, " \
"ival=0x%" #mod "x" \
/* Hex dump of masked frac bits; 'fraw' includes shift */ \
"\n\tfraw=0x%0" #hexpad #mod "x, " \
"fabsval=0x%" #mod "x, " \
"fval=0x%" #mod "x" \
"%s" \
postfmt
#define Q_DEBUGFMT(q, prefmt, postfmt) \
sizeof(q) == 8 ? Q_DEBUGFMT_(prefmt, postfmt, j, 16) : \
sizeof(q) == 4 ? Q_DEBUGFMT_(prefmt, postfmt, , 8) : \
sizeof(q) == 2 ? Q_DEBUGFMT_(prefmt, postfmt, h, 4) : \
sizeof(q) == 1 ? Q_DEBUGFMT_(prefmt, postfmt, hh, 2) : \
prefmt "\"%s\"@%p: invalid" postfmt \
/*
* Returns a format string and data suitable for printf-like rendering
* e.g. Print to console with a trailing newline: printf(Q_DEBUG(q, "", "\n"));
*/
#define Q_DEBUG(q, prefmt, postfmt, incfmt) \
Q_DEBUGFMT(q, prefmt, postfmt) \
, #q \
, &(q) \
, Q_SIGNED(q) ? 's' : 'u' \
, Q_NTBITS(q) \
, Q_NIBITS(q) \
, Q_NFBITS(q) \
, Q_RPSHFT(q) \
, Q_IMINVAL(q) \
, Q_IMAXVAL(q) \
, (q) \
, Q_IRAWMASK(q) \
, Q_FRAWMASK(q) \
, Q_TC(q, Q_CRAWMASK(q)) \
, Q_IFRAWMASK(q) \
, Q_GIRAW(q) \
, Q_GIABSVAL(q) \
, Q_GIVAL(q) \
, Q_GFRAW(q) \
, Q_GFABSVAL(q) \
, Q_GFVAL(q) \
, (incfmt) ? Q_DEBUGFMT(q, "\nfmt:", "") : "" \
/*
* If precision differs, attempt to normalise to the greater precision that
* preserves the integer component of both 'a' and 'b'.
*/
#define Q_NORMPREC(a, b) \
({ \
int _perr = 0, _relprec = Q_RELPREC(*(a), b); \
if (_relprec != 0) \
_perr = ERANGE; /* XXXLAS: Do precision normalisation! */\
_perr; \
})
/* Clone r's control bits and int/frac value into 'l'. */
#define Q_QCLONEQ(l, r) \
({ \
Q_BT(*(l)) _l = Q_GCVAL(r); \
int _err = Q_QCANREPQ(r, _l); \
if (!_err) { \
*(l) = _l; \
Q_SIFVAL(*(l), Q_GIFVAL(r)); \
} \
_err; \
})
/* Copy r's int/frac vals into 'l', retaining 'l's precision and signedness. */
#define Q_QCPYVALQ(l, r) \
({ \
int _err = Q_QCANREPQ(r, *(l)); \
if (!_err) \
Q_SIFVALS(*(l), Q_GIVAL(r), Q_GFVAL(r)); \
_err; \
})
#define Q_QADDSUBQ(a, b, eop) \
({ \
int _aserr; \
if ((_aserr = Q_NORMPREC(a, b))) while(0); /* NOP */ \
else if ((eop) == '+') { \
if (Q_IFMAXVAL(*(a)) - Q_GIFABSVAL(b) < Q_GIFVAL(*(a))) \
_aserr = EOVERFLOW; /* [+/-a + +b] > max(a) */ \
else \
Q_SIFVAL(*(a), Q_GIFVAL(*(a)) + Q_TC(*(a), \
Q_GIFABSVAL(b))); \
} else { /* eop == '-' */ \
if (Q_IFMINVAL(*(a)) + Q_GIFABSVAL(b) > Q_GIFVAL(*(a))) \
_aserr = EOVERFLOW; /* [+/-a - +b] < min(a) */ \
else \
Q_SIFVAL(*(a), Q_GIFVAL(*(a)) - Q_TC(*(a), \
Q_GIFABSVAL(b))); \
} \
_aserr; \
})
#define Q_QADDQ(a, b) Q_QADDSUBQ(a, b, (Q_LTZ(b) ? '-' : '+'))
#define Q_QSUBQ(a, b) Q_QADDSUBQ(a, b, (Q_LTZ(b) ? '+' : '-'))
#define Q_QDIVQ(a, b) \
({ \
int _err; \
if ((_err = Q_NORMPREC(a, b))) while(0); /* NOP */ \
else if (Q_GIFABSVAL(b) == 0 || (!Q_SIGNED(*(a)) && Q_LTZ(b))) \
_err = EINVAL; /* Divide by zero or cannot represent. */\
/* XXXLAS: Handle overflow. */ \
else if (Q_GIFABSVAL(*(a)) != 0) { /* Result expected. */ \
Q_SIFVAL(*(a), \
((Q_GIVAL(*(a)) << Q_NFBITS(*(a))) / Q_GIFVAL(b)) + \
(Q_GFVAL(b) == 0 ? 0 : \
((Q_GFVAL(*(a)) << Q_NFBITS(*(a))) / Q_GFVAL(b)))); \
} \
_err; \
})
#define Q_QMULQ(a, b) \
({ \
int _mulerr; \
if ((_mulerr = Q_NORMPREC(a, b))) while(0); /* NOP */ \
else if (!Q_SIGNED(*(a)) && Q_LTZ(b)) \
_mulerr = EINVAL; \
else if (Q_GIFABSVAL(b) != 0 && \
Q_IFMAXVAL(*(a)) / Q_GIFABSVAL(b) < Q_GIFABSVAL(*(a))) \
_mulerr = EOVERFLOW; \
else \
Q_SIFVAL(*(a), (Q_GIFVAL(*(a)) * Q_GIFVAL(b)) >> \
Q_NFBITS(*(a))); \
_mulerr; \
})
#define Q_QCPYVALI(q, i) \
({ \
int _err = Q_QCANREPI(*(q), i); \
if (!_err) \
Q_SIFVAL(*(q), Q_SHL(*(q), i)); \
_err; \
})
#define Q_QADDSUBI(q, i, eop) \
({ \
int _aserr = 0; \
if (Q_NTBITS(*(q)) < (uint32_t)flsll(Q_ABS(i))) \
_aserr = EOVERFLOW; /* i cannot fit in q's type. */ \
else if ((eop) == '+') { \
if (Q_IMAXVAL(*(q)) - Q_TC(*(q), Q_ABS(i)) < \
Q_GIVAL(*(q))) \
_aserr = EOVERFLOW; /* [+/-q + +i] > max(q) */ \
else \
Q_SIFVAL(*(q), Q_GIFVAL(*(q)) + \
Q_SHL(*(q), Q_ABS(i))); \
} else { /* eop == '-' */ \
if (Q_IMINVAL(*(q)) + Q_ABS(i) > Q_GIVAL(*(q))) \
_aserr = EOVERFLOW; /* [+/-q - +i] < min(q) */ \
else \
Q_SIFVAL(*(q), Q_GIFVAL(*(q)) - \
Q_SHL(*(q), Q_ABS(i))); \
} \
_aserr; \
})
#define Q_QADDI(q, i) Q_QADDSUBI(q, i, (Q_LTZ(i) ? '-' : '+'))
#define Q_QSUBI(q, i) Q_QADDSUBI(q, i, (Q_LTZ(i) ? '+' : '-'))
#define Q_QDIVI(q, i) \
({ \
int _diverr = 0; \
if ((i) == 0 || (!Q_SIGNED(*(q)) && Q_LTZ(i))) \
_diverr = EINVAL; /* Divide by zero or cannot represent. */\
else if (Q_GIFABSVAL(*(q)) != 0) { /* Result expected. */ \
Q_SIFVAL(*(q), Q_GIFVAL(*(q)) / Q_TC(*(q), i)); \
if (Q_GIFABSVAL(*(q)) == 0) \
_diverr = ERANGE; /* q underflow. */ \
} \
_diverr; \
})
#define Q_QMULI(q, i) \
({ \
int _mulerr = 0; \
if (!Q_SIGNED(*(q)) && Q_LTZ(i)) \
_mulerr = EINVAL; /* Cannot represent. */ \
else if ((i) != 0 && Q_IFMAXVAL(*(q)) / Q_TC(*(q), Q_ABS(i)) < \
Q_GIFABSVAL(*(q))) \
_mulerr = EOVERFLOW; \
else \
Q_SIFVAL(*(q), Q_GIFVAL(*(q)) * Q_TC(*(q), i)); \
_mulerr; \
})
#define Q_QFRACI(q, in, id) \
({ \
uint64_t _tmp; \
int _err = 0; \
if ((id) == 0) \
_err = EINVAL; /* Divide by zero. */ \
else if ((in) == 0) \
Q_SIFVAL(*(q), in); \
else if ((_tmp = Q_ABS(in)) > (UINT64_MAX >> Q_RPSHFT(*(q)))) \
_err = EOVERFLOW; /* _tmp overflow. */ \
else { \
_tmp = Q_SHL(*(q), _tmp) / Q_ABS(id); \
if (Q_QCANREPI(*(q), _tmp & Q_IFVALIMASK(*(q)))) \
_err = EOVERFLOW; /* q overflow. */ \
else { \
Q_SIFVAL(*(q), _tmp); \
Q_SSIGN(*(q), (Q_LTZ(in) && !Q_LTZ(id)) || \
(!Q_LTZ(in) && Q_LTZ(id))); \
if (_tmp == 0) \
_err = ERANGE; /* q underflow. */ \
} \
} \
_err; \
})
#endif /* _SYS_QMATH_H_ */

View File

@ -2,7 +2,7 @@
TESTSDIR= ${TESTSBASE}/sys/sys
ATF_TESTS_C= bitstring_test rb_test splay_test
ATF_TESTS_C= bitstring_test qmath_test rb_test splay_test
WARNS?= 5

653
tests/sys/sys/qmath_test.c Normal file
View File

@ -0,0 +1,653 @@
/*-
* 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.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 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$
*/
/*
* Author: Lawrence Stewart <lstewart@netflix.com>
*/
#include <sys/param.h>
#include <sys/qmath.h>
#include <errno.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <atf-c.h>
#define QTEST_IV 3
#define QTEST_IVSTR "3.00"
#define QTEST_RPSHFT 2
#define QTEST_INTBITS(q) (Q_NTBITS(q) - Q_SIGNED(q) - Q_NFBITS(q) - Q_NCBITS)
#define QTEST_QITRUNC(q, iv) ((iv) >> Q_RPSHFT(q))
#define QTEST_FFACTOR 32.0
#define bitsperrand 31
#define GENRAND(a, lb, ub) \
({ \
int _rembits; \
do { \
_rembits = Q_BITSPERBASEUP(ub) + Q_LTZ(lb); \
*(a) = (__typeof(*(a)))0; \
while (_rembits > 0) { \
*(a) |= (((uint64_t)random()) & \
((1ULL << (_rembits > bitsperrand ? \
bitsperrand : _rembits)) - 1)); \
*(a) <<= (_rembits - (_rembits > bitsperrand ? \
bitsperrand : _rembits)); \
_rembits -= bitsperrand; \
} \
*(a) += lb; \
} while (*(a) < (lb) || (uint64_t)*(a) > (ub)); \
*(a); \
})
/*
* Smoke tests for basic qmath operations, such as initialization
* or string formatting.
*/
ATF_TC_WITHOUT_HEAD(basic_s8q);
ATF_TC_BODY(basic_s8q, tc)
{
char buf[128];
s8q_t s8;
Q_INI(&s8, QTEST_IV, 0, QTEST_RPSHFT);
Q_TOSTR(s8, -1, 10, buf, sizeof(buf));
ATF_CHECK_STREQ(QTEST_IVSTR, buf);
ATF_CHECK_EQ(sizeof(s8) << 3, Q_NTBITS(s8));
ATF_CHECK_EQ(QTEST_RPSHFT, Q_NFBITS(s8));
ATF_CHECK_EQ(QTEST_INTBITS(s8), Q_NIBITS(s8));
ATF_CHECK_EQ(QTEST_QITRUNC(s8, INT8_MAX), Q_IMAXVAL(s8));
ATF_CHECK_EQ(-Q_IMAXVAL(s8), Q_IMINVAL(s8));
}
ATF_TC_WITHOUT_HEAD(basic_s16q);
ATF_TC_BODY(basic_s16q, tc)
{
char buf[128];
s16q_t s16;
Q_INI(&s16, QTEST_IV, 0, QTEST_RPSHFT);
Q_TOSTR(s16, -1, 10, buf, sizeof(buf));
ATF_CHECK_STREQ(QTEST_IVSTR, buf);
ATF_CHECK_EQ(sizeof(s16) << 3, Q_NTBITS(s16));
ATF_CHECK_EQ(QTEST_RPSHFT, Q_NFBITS(s16));
ATF_CHECK_EQ(QTEST_INTBITS(s16), Q_NIBITS(s16));
ATF_CHECK_EQ(QTEST_QITRUNC(s16, INT16_MAX), Q_IMAXVAL(s16));
ATF_CHECK_EQ(-Q_IMAXVAL(s16), Q_IMINVAL(s16));
}
ATF_TC_WITHOUT_HEAD(basic_s32q);
ATF_TC_BODY(basic_s32q, tc)
{
char buf[128];
s32q_t s32;
Q_INI(&s32, QTEST_IV, 0, QTEST_RPSHFT);
Q_TOSTR(s32, -1, 10, buf, sizeof(buf));
ATF_CHECK_STREQ(QTEST_IVSTR, buf);
ATF_CHECK_EQ(sizeof(s32) << 3, Q_NTBITS(s32));
ATF_CHECK_EQ(QTEST_RPSHFT, Q_NFBITS(s32));
ATF_CHECK_EQ(QTEST_INTBITS(s32), Q_NIBITS(s32));
ATF_CHECK_EQ(QTEST_QITRUNC(s32, INT32_MAX), Q_IMAXVAL(s32));
ATF_CHECK_EQ(-Q_IMAXVAL(s32), Q_IMINVAL(s32));
}
ATF_TC_WITHOUT_HEAD(basic_s64q);
ATF_TC_BODY(basic_s64q, tc)
{
char buf[128];
s64q_t s64;
Q_INI(&s64, QTEST_IV, 0, QTEST_RPSHFT);
Q_TOSTR(s64, -1, 10, buf, sizeof(buf));
ATF_CHECK_STREQ(QTEST_IVSTR, buf);
ATF_CHECK_EQ(sizeof(s64) << 3, Q_NTBITS(s64));
ATF_CHECK_EQ(QTEST_RPSHFT, Q_NFBITS(s64));
ATF_CHECK_EQ(QTEST_INTBITS(s64), Q_NIBITS(s64));
ATF_CHECK_EQ(QTEST_QITRUNC(s64, INT64_MAX), Q_IMAXVAL(s64));
ATF_CHECK_EQ(-Q_IMAXVAL(s64), Q_IMINVAL(s64));
}
ATF_TC_WITHOUT_HEAD(basic_u8q);
ATF_TC_BODY(basic_u8q, tc)
{
char buf[128];
u8q_t u8;
Q_INI(&u8, QTEST_IV, 0, QTEST_RPSHFT);
Q_TOSTR(u8, -1, 10, buf, sizeof(buf));
ATF_CHECK_STREQ(QTEST_IVSTR, buf);
ATF_CHECK_EQ(sizeof(u8) << 3, Q_NTBITS(u8));
ATF_CHECK_EQ(QTEST_RPSHFT, Q_NFBITS(u8));
ATF_CHECK_EQ(QTEST_INTBITS(u8), Q_NIBITS(u8));
ATF_CHECK_EQ(QTEST_QITRUNC(u8, UINT8_MAX), Q_IMAXVAL(u8));
ATF_CHECK_EQ(0, Q_IMINVAL(u8));
}
ATF_TC_WITHOUT_HEAD(basic_u16q);
ATF_TC_BODY(basic_u16q, tc)
{
char buf[128];
u16q_t u16;
Q_INI(&u16, QTEST_IV, 0, QTEST_RPSHFT);
Q_TOSTR(u16, -1, 10, buf, sizeof(buf));
ATF_CHECK_STREQ(QTEST_IVSTR, buf);
ATF_CHECK_EQ(sizeof(u16) << 3, Q_NTBITS(u16));
ATF_CHECK_EQ(QTEST_RPSHFT, Q_NFBITS(u16));
ATF_CHECK_EQ(QTEST_INTBITS(u16), Q_NIBITS(u16));
ATF_CHECK_EQ(QTEST_QITRUNC(u16, UINT16_MAX), Q_IMAXVAL(u16));
ATF_CHECK_EQ(0, Q_IMINVAL(u16));
}
ATF_TC_WITHOUT_HEAD(basic_u32q);
ATF_TC_BODY(basic_u32q, tc)
{
char buf[128];
u32q_t u32;
Q_INI(&u32, QTEST_IV, 0, QTEST_RPSHFT);
Q_TOSTR(u32, -1, 10, buf, sizeof(buf));
ATF_CHECK_STREQ(QTEST_IVSTR, buf);
ATF_CHECK_EQ(sizeof(u32) << 3, Q_NTBITS(u32));
ATF_CHECK_EQ(QTEST_RPSHFT, Q_NFBITS(u32));
ATF_CHECK_EQ(QTEST_INTBITS(u32), Q_NIBITS(u32));
ATF_CHECK_EQ(QTEST_QITRUNC(u32, UINT32_MAX), Q_IMAXVAL(u32));
ATF_CHECK_EQ(0, Q_IMINVAL(u32));
}
ATF_TC_WITHOUT_HEAD(basic_u64q);
ATF_TC_BODY(basic_u64q, tc)
{
char buf[128];
u64q_t u64;
Q_INI(&u64, QTEST_IV, 0, QTEST_RPSHFT);
Q_TOSTR(u64, -1, 10, buf, sizeof(buf));
ATF_CHECK_STREQ(QTEST_IVSTR, buf);
ATF_CHECK_EQ(sizeof(u64) << 3, Q_NTBITS(u64));
ATF_CHECK_EQ(QTEST_RPSHFT, Q_NFBITS(u64));
ATF_CHECK_EQ(QTEST_INTBITS(u64), Q_NIBITS(u64));
ATF_CHECK_EQ(QTEST_QITRUNC(u64, UINT64_MAX), Q_IMAXVAL(u64));
ATF_CHECK_EQ(0, Q_IMINVAL(u64));
}
/*
* Test Q_QMULQ(3) by applying it to two random Q numbers and comparing
* the result with its floating-point counterpart.
*/
ATF_TC_WITHOUT_HEAD(qmulq_s64q);
ATF_TC_BODY(qmulq_s64q, tc)
{
s64q_t a_s64q, b_s64q, r_s64q;
double a_dbl, b_dbl, r_dbl, maxe_dbl, delta_dbl;
int64_t a_int, b_int;
int error;
srandomdev();
for (int i = 0; i < 10;) {
GENRAND(&a_s64q, INT64_MIN, UINT64_MAX);
GENRAND(&b_s64q, INT64_MIN, UINT64_MAX);
/*
* XXX: We cheat a bit, to stand any chance of multiplying
* without overflow.
*/
error = Q_QDIVQ(&a_s64q, b_s64q);
if (error == EOVERFLOW || error == ERANGE)
continue;
ATF_CHECK_EQ(0, error);
/*
* XXXLAS: Until Qmath handles precision normalisation, only
* test with equal precision.
*/
Q_SCVAL(b_s64q, Q_GCVAL(a_s64q));
a_int = Q_GIVAL(a_s64q);
b_int = Q_GIVAL(b_s64q);
/* Q<op>Q testing. */
a_dbl = Q_Q2D(a_s64q);
b_dbl = Q_Q2D(b_s64q);
r_s64q = a_s64q;
error = Q_QMULQ(&r_s64q, b_s64q);
if (error == EOVERFLOW || error == ERANGE)
continue;
i++;
ATF_CHECK_EQ(0, error);
r_dbl = a_dbl * b_dbl;
#ifdef notyet
maxe_dbl = fabs(((1.0 / Q_NFBITS(a_s64q)) * (double)b_int) +
((1.0 / Q_NFBITS(b_s64q)) * (double)a_int));
#else
maxe_dbl = QTEST_FFACTOR;
#endif
delta_dbl = fabs(r_dbl - Q_Q2D(r_s64q));
ATF_CHECK_MSG(delta_dbl <= maxe_dbl,
"\tQMULQ(%10f * %10f): |%10f - %10f| = %10f "
"(max err %f)\n",
Q_Q2D(a_s64q), Q_Q2D(b_s64q), Q_Q2D(r_s64q), r_dbl,
delta_dbl, maxe_dbl);
}
}
/*
* Test Q_QDIVQ(3) by applying it to two random Q numbers and comparing
* the result with its floating-point counterpart.
*/
ATF_TC_WITHOUT_HEAD(qdivq_s64q);
ATF_TC_BODY(qdivq_s64q, tc)
{
s64q_t a_s64q, b_s64q, r_s64q;
double a_dbl, b_dbl, r_dbl, maxe_dbl, delta_dbl;
int64_t a_int, b_int;
int error;
srandomdev();
for (int i = 0; i < 10; i++) {
GENRAND(&a_s64q, INT64_MIN, UINT64_MAX);
GENRAND(&b_s64q, INT64_MIN, UINT64_MAX);
/*
* XXXLAS: Until Qmath handles precision normalisation, only
* test with equal precision.
*/
Q_SCVAL(b_s64q, Q_GCVAL(a_s64q));
a_int = Q_GIVAL(a_s64q);
b_int = Q_GIVAL(b_s64q);
/* Q<op>Q testing. */
a_dbl = Q_Q2D(a_s64q);
b_dbl = Q_Q2D(b_s64q);
r_s64q = a_s64q;
error = Q_QDIVQ(&r_s64q, b_s64q);
ATF_CHECK_EQ(0, error);
r_dbl = a_dbl / b_dbl;
#ifdef notyet
maxe_dbl = fabs(1.0 / (1ULL << Q_NFBITS(a_s64q)));
#else
maxe_dbl = QTEST_FFACTOR * 2;
#endif
delta_dbl = fabs(r_dbl - Q_Q2D(r_s64q));
ATF_CHECK_MSG(delta_dbl <= maxe_dbl,
"\tQDIVQ(%10f / %10f): |%10f - %10f| = %10f "
"(max err %f)\n",
Q_Q2D(a_s64q), Q_Q2D(b_s64q), Q_Q2D(r_s64q), r_dbl,
delta_dbl, maxe_dbl);
}
}
/*
* Test Q_QADDQ(3) by applying it to two random Q numbers and comparing
* the result with its floating-point counterpart.
*/
ATF_TC_WITHOUT_HEAD(qaddq_s64q);
ATF_TC_BODY(qaddq_s64q, tc)
{
s64q_t a_s64q, b_s64q, r_s64q;
double a_dbl, b_dbl, r_dbl, maxe_dbl, delta_dbl;
int64_t a_int, b_int;
int error;
srandomdev();
for (int i = 0; i < 10;) {
GENRAND(&a_s64q, INT64_MIN, UINT64_MAX);
GENRAND(&b_s64q, INT64_MIN, UINT64_MAX);
/*
* XXXLAS: Until Qmath handles precision normalisation, only
* test with equal precision.
*/
Q_SCVAL(b_s64q, Q_GCVAL(a_s64q));
a_int = Q_GIVAL(a_s64q);
b_int = Q_GIVAL(b_s64q);
/* Q<op>Q testing. */
a_dbl = Q_Q2D(a_s64q);
b_dbl = Q_Q2D(b_s64q);
r_s64q = a_s64q;
error = Q_QADDQ(&r_s64q, b_s64q);
if (error == EOVERFLOW || error == ERANGE)
continue;
i++;
ATF_CHECK_EQ(0, error);
r_dbl = a_dbl + b_dbl;
#ifdef notyet
maxe_dbl = 0.5;
#else
maxe_dbl = QTEST_FFACTOR;
#endif
delta_dbl = fabs(r_dbl - Q_Q2D(r_s64q));
ATF_CHECK_MSG(delta_dbl <= maxe_dbl,
"\tQADDQ(%10f + %10f): |%10f - %10f| = %10f "
"(max err %f)\n",
Q_Q2D(a_s64q), Q_Q2D(b_s64q), Q_Q2D(r_s64q), r_dbl,
delta_dbl, maxe_dbl);
}
}
/*
* Test Q_QSUBQ(3) by applying it to two random Q numbers and comparing
* the result with its floating-point counterpart.
*/
ATF_TC_WITHOUT_HEAD(qsubq_s64q);
ATF_TC_BODY(qsubq_s64q, tc)
{
s64q_t a_s64q, b_s64q, r_s64q;
double a_dbl, b_dbl, r_dbl, maxe_dbl, delta_dbl;
int64_t a_int, b_int;
int error;
srandomdev();
for (int i = 0; i < 10; i++) {
GENRAND(&a_s64q, INT64_MIN, UINT64_MAX);
GENRAND(&b_s64q, INT64_MIN, UINT64_MAX);
/*
* XXXLAS: Until Qmath handles precision normalisation, only
* test with equal precision.
*/
Q_SCVAL(b_s64q, Q_GCVAL(a_s64q));
a_int = Q_GIVAL(a_s64q);
b_int = Q_GIVAL(b_s64q);
/* Q<op>Q testing. */
a_dbl = Q_Q2D(a_s64q);
b_dbl = Q_Q2D(b_s64q);
r_s64q = a_s64q;
error = Q_QSUBQ(&r_s64q, b_s64q);
ATF_CHECK_EQ(0, error);
r_dbl = a_dbl - b_dbl;
#ifdef notyet
maxe_dbl = 0.5;
#else
maxe_dbl = QTEST_FFACTOR;
#endif
delta_dbl = fabs(r_dbl - Q_Q2D(r_s64q));
ATF_CHECK_MSG(delta_dbl <= maxe_dbl,
"\tQSUBQ(%10f - %10f): |%10f - %10f| = %10f "
"(max err %f)\n",
Q_Q2D(a_s64q), Q_Q2D(b_s64q), Q_Q2D(r_s64q), r_dbl,
delta_dbl, maxe_dbl);
}
}
/*
* Test Q_QFRACI(3) by applying it to two random integers and comparing
* the result with its floating-point counterpart.
*/
ATF_TC_WITHOUT_HEAD(qfraci_s64q);
ATF_TC_BODY(qfraci_s64q, tc)
{
s64q_t a_s64q, b_s64q, r_s64q;
double a_dbl, b_dbl, r_dbl, maxe_dbl, delta_dbl;
int64_t a_int, b_int;
int error;
srandomdev();
for (int i = 0; i < 10;) {
GENRAND(&a_s64q, INT64_MIN, UINT64_MAX);
GENRAND(&b_s64q, INT64_MIN, UINT64_MAX);
/*
* XXXLAS: Until Qmath handles precision normalisation, only
* test with equal precision.
*/
Q_SCVAL(b_s64q, Q_GCVAL(a_s64q));
a_int = Q_GIVAL(a_s64q);
b_int = Q_GIVAL(b_s64q);
/* Q<op>I testing. */
a_dbl = a_int;
b_dbl = b_int;
Q_INI(&r_s64q, 0, 0, Q_NFBITS(a_s64q));
error = Q_QFRACI(&r_s64q, a_int, b_int);
if (error == EOVERFLOW || error == ERANGE || error == EINVAL)
continue;
i++;
ATF_CHECK_EQ(0, error);
r_dbl = a_dbl / b_dbl;
maxe_dbl = fabs(1.0 / Q_NFBITS(a_s64q));
delta_dbl = fabs(r_dbl - Q_Q2D(r_s64q));
ATF_CHECK_MSG(delta_dbl <= maxe_dbl,
"\tQFRACI(%ld / %ld): |%10f - %10f| = %10f "
"(max err %f)\n",
a_int, b_int, Q_Q2D(r_s64q), r_dbl, delta_dbl,
maxe_dbl);
}
}
/*
* Test Q_QMULI(3) by applying it to a random Q number and a random integer
* and comparing the result with its floating-point counterpart.
*/
ATF_TC_WITHOUT_HEAD(qmuli_s64q);
ATF_TC_BODY(qmuli_s64q, tc)
{
s64q_t a_s64q, b_s64q, r_s64q;
double a_dbl, b_dbl, r_dbl, maxe_dbl, delta_dbl;
int64_t a_int, b_int;
int error;
srandomdev();
for (int i = 0; i < 10;) {
GENRAND(&a_s64q, INT64_MIN, UINT64_MAX);
GENRAND(&b_s64q, INT64_MIN, UINT64_MAX);
/*
* XXXLAS: Until Qmath handles precision normalisation, only
* test with equal precision.
*/
Q_SCVAL(b_s64q, Q_GCVAL(a_s64q));
a_int = Q_GIVAL(a_s64q);
b_int = Q_GIVAL(b_s64q);
/* Q<op>I testing. */
a_dbl = a_int;
b_dbl = b_int;
Q_INI(&r_s64q, a_int, 0, Q_NFBITS(a_s64q));
error = Q_QMULI(&r_s64q, b_int);
if (error == EOVERFLOW || error == ERANGE)
continue;
i++;
ATF_CHECK_EQ(0, error);
r_dbl = a_dbl * b_dbl;
maxe_dbl = fabs((1.0 / Q_NFBITS(a_s64q)) * (double)b_int);
delta_dbl = fabs(r_dbl - Q_Q2D(r_s64q));
ATF_CHECK_MSG(delta_dbl <= maxe_dbl,
"\tQMULI(%ld * %ld): |%10f - %10f| = %10f "
"(max err %f)\n",
a_int, b_int, Q_Q2D(r_s64q), r_dbl, delta_dbl,
maxe_dbl);
}
}
/*
* Test Q_QADDI(3) by applying it to a random Q number and a random integer
* and comparing the result with its floating-point counterpart.
*/
ATF_TC_WITHOUT_HEAD(qaddi_s64q);
ATF_TC_BODY(qaddi_s64q, tc)
{
s64q_t a_s64q, b_s64q, r_s64q;
double a_dbl, b_dbl, r_dbl, maxe_dbl, delta_dbl;
int64_t a_int, b_int;
int error;
srandomdev();
for (int i = 0; i < 10;) {
GENRAND(&a_s64q, INT64_MIN, UINT64_MAX);
GENRAND(&b_s64q, INT64_MIN, UINT64_MAX);
/*
* XXXLAS: Until Qmath handles precision normalisation, only
* test with equal precision.
*/
Q_SCVAL(b_s64q, Q_GCVAL(a_s64q));
a_int = Q_GIVAL(a_s64q);
b_int = Q_GIVAL(b_s64q);
/* Q<op>I testing. */
a_dbl = a_int;
b_dbl = b_int;
Q_INI(&r_s64q, a_int, 0, Q_NFBITS(a_s64q));
error = Q_QADDI(&r_s64q, b_int);
if (error == EOVERFLOW || error == ERANGE)
continue;
i++;
ATF_CHECK_EQ(0, error);
r_dbl = a_dbl + b_dbl;
#ifdef notyet
maxe_dbl = 0.5;
#else
maxe_dbl = QTEST_FFACTOR;
#endif
delta_dbl = fabs(r_dbl - Q_Q2D(r_s64q));
ATF_CHECK_MSG(delta_dbl <= maxe_dbl,
"\tQADDI(%ld + %ld): |%10f - %10f| = %10f "
"(max err %f)\n",
a_int, b_int, Q_Q2D(r_s64q), r_dbl, delta_dbl,
maxe_dbl);
}
}
/*
* Test Q_QSUBI(3) by applying it to a random Q number and a random integer
* and comparing the result with its floating-point counterpart.
*/
ATF_TC_WITHOUT_HEAD(qsubi_s64q);
ATF_TC_BODY(qsubi_s64q, tc)
{
s64q_t a_s64q, b_s64q, r_s64q;
double a_dbl, b_dbl, r_dbl, maxe_dbl, delta_dbl;
int64_t a_int, b_int;
int error;
srandomdev();
for (int i = 0; i < 10; i++) {
GENRAND(&a_s64q, INT64_MIN, UINT64_MAX);
GENRAND(&b_s64q, INT64_MIN, UINT64_MAX);
/*
* XXXLAS: Until Qmath handles precision normalisation, only
* test with equal precision.
*/
Q_SCVAL(b_s64q, Q_GCVAL(a_s64q));
a_int = Q_GIVAL(a_s64q);
b_int = Q_GIVAL(b_s64q);
/* Q<op>I testing. */
a_dbl = a_int;
b_dbl = b_int;
Q_INI(&r_s64q, a_int, 0, Q_NFBITS(a_s64q));
error = Q_QSUBI(&r_s64q, b_int);
ATF_CHECK_EQ(0, error);
r_dbl = a_dbl - b_dbl;
#ifdef notyet
maxe_dbl = 0.5;
#else
maxe_dbl = QTEST_FFACTOR;
#endif
delta_dbl = fabs(r_dbl - Q_Q2D(r_s64q));
ATF_CHECK_MSG(delta_dbl <= maxe_dbl,
"\tQSUBI(%ld - %ld): |%10f - %10f| = %10f "
"(max err %f)\n",
a_int, b_int, Q_Q2D(r_s64q), r_dbl, delta_dbl,
maxe_dbl);
}
}
/*
* Calculate area of a circle with r=42.
*/
ATF_TC_WITHOUT_HEAD(circle_u64q);
ATF_TC_BODY(circle_u64q, tc)
{
char buf[128];
u64q_t a, pi, r;
int error;
Q_INI(&a, 0, 0, 16);
Q_INI(&pi, 3, 14159, 16);
Q_INI(&r, 4, 2, 16);
error = Q_QCLONEQ(&a, r);
ATF_CHECK_EQ(0, error);
error = Q_QMULQ(&a, r);
ATF_CHECK_EQ(0, error);
error = Q_QMULQ(&a, pi);
ATF_CHECK_EQ(0, error);
Q_TOSTR(a, -1, 10, buf, sizeof(buf));
ATF_CHECK_STREQ("55.4174804687500000", buf);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, basic_s8q);
ATF_TP_ADD_TC(tp, basic_s16q);
ATF_TP_ADD_TC(tp, basic_s32q);
ATF_TP_ADD_TC(tp, basic_s64q);
ATF_TP_ADD_TC(tp, basic_u8q);
ATF_TP_ADD_TC(tp, basic_u16q);
ATF_TP_ADD_TC(tp, basic_u32q);
ATF_TP_ADD_TC(tp, basic_u64q);
ATF_TP_ADD_TC(tp, qmulq_s64q);
ATF_TP_ADD_TC(tp, qdivq_s64q);
ATF_TP_ADD_TC(tp, qaddq_s64q);
ATF_TP_ADD_TC(tp, qsubq_s64q);
ATF_TP_ADD_TC(tp, qfraci_s64q);
ATF_TP_ADD_TC(tp, qmuli_s64q);
ATF_TP_ADD_TC(tp, qaddi_s64q);
ATF_TP_ADD_TC(tp, qsubi_s64q);
ATF_TP_ADD_TC(tp, circle_u64q);
return (atf_no_error());
}