#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 s64q_t smaxq_t;
typedef u64q_t umaxq_t;
#if defined(__GNUC__) && !defined(__clang__)
#define Q_BT(q) __typeof(1 * q)
#else
#define Q_BT(q) __typeof(q)
#endif
#define Q_TC(q, v) ((__typeof(q))(v))
#define Q_NTBITS(q) ((uint32_t)(sizeof(q) << 3))
#define Q_NCBITS ((uint32_t)3)
#define Q_NFCBITS(q) \
((uint32_t)(((Q_GCRAW(q) & 0x3) + 1) << ((Q_GCRAW(q) & 0x4) ? 4 : 1)))
#define Q_MINNFBITS(q) ((uint32_t)(2))
#define Q_MAXNFBITS(q) ((uint32_t)(Q_NTBITS(q) - Q_SIGNED(q) - Q_NCBITS))
#define Q_NFBITS(q) \
(Q_NFCBITS(q) > Q_MAXNFBITS(q) ? Q_MAXNFBITS(q) : Q_NFCBITS(q))
#define Q_NIBITS(q) ((uint32_t)(Q_NTBITS(q) - Q_RPSHFT(q) - Q_SIGNED(q)))
#define Q_RPSHFT(q) (Q_NCBITS + Q_NFBITS(q))
#define Q_SIGNSHFT(q) (Q_NTBITS(q) - 1)
#define Q_SSIGN(q, isneg) \
((q) = ((Q_SIGNED(q) && (isneg)) ? (q) | (1ULL << Q_SIGNSHFT(q)) : \
(q) & ~(1ULL << Q_SIGNSHFT(q))))
#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))
#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))
#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))
#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))
#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)
#define Q_NIBITS2NCHARS(nbits, base) \
({ \
int _bitsperbase = Q_BITSPERBASE(base, DOWN); \
(((nbits) + _bitsperbase - 1) / _bitsperbase); \
})
#define Q_NFBITS2NCHARS(nbits, base) (nbits)
#define Q_MAXSTRLEN(q, base) \
(2 + Q_NIBITS2NCHARS(Q_NIBITS(q), base) + \
Q_NFBITS2NCHARS(Q_NFBITS(q), base) + Q_SIGNED(q))
#define Q_IBITS2CH(q, bits, base) \
({ \
__typeof(bits) _tmp = (bits) / (base); \
int _idx = (bits) - (_tmp * (base)); \
(bits) = _tmp; \
"0123456789abcdef"[_idx]; \
})
#define Q_FBITS2CH(q, bits, base) \
({ \
int _carry = 0, _idx, _nfbits = Q_NFBITS(q), _shift = 0; \
\
if (_nfbits > Q_BITSPERBASEUP(base)) { \
\
_shift = _nfbits >> 1; \
_carry = (((bits) & ((1ULL << _shift) - 1)) * (base)) >> _shift;\
} \
_idx = ((((bits) >> _shift) * (base)) + _carry) >> (_nfbits - _shift);\
(bits) *= (base); \
(bits) &= (1ULL << _nfbits) - 1; \
"0123456789abcdef"[_idx]; \
})
#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 { \
\
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; \
while (_i-- > 0 && _r != NULL) { \
\
*_s = *(_r + _i); \
*(_r + _i) = *(_s - _i - 1); \
*(_s - _i - 1) = *_s; \
} \
_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) { \
\
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'; \
} \
\
(_r != NULL ? _s : _r); \
})
#define Q_SHL(q, iv) \
(Q_LTZ(iv) ? -(int64_t)(Q_ABS(iv) << Q_NFBITS(q)) : \
Q_TC(q, iv) << Q_NFBITS(q))
#define Q_RELPREC(a, b) ((int)Q_NFBITS(a) - (int)Q_NFBITS(b))
#define Q_CTRLINI(rpshft) \
(((rpshft) <= 8) ? (((rpshft) - 1) >> 1) : (0x4 | (((rpshft) - 1) >> 4)))
#define Q_DFV2BFV(dfv, nfbits) \
({ \
uint64_t _bfv = 0, _thresh = 5, _tmp = dfv; \
int _i = sizeof(""#dfv) - 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; \
})
#define Q_INI(q, iv, dfv, rpshft) \
({ \
(*(q)) = Q_CTRLINI(rpshft); \
Q_SIFVALS(*(q), iv, Q_DFV2BFV(dfv, Q_NFBITS(*(q)))); \
})
#define Q_PRECEQ(a, b) (Q_NFBITS(a) == Q_NFBITS(b))
#define Q_SIGNED(n) (Q_TC(n, -1) < 0)
#define Q_LTZ(n) (Q_SIGNED(n) && ((n) & Q_SRAWMASK(n)))
#define Q_ABS(n) (Q_LTZ(n) ? -(n) : (n))
#define Q_QABS(q) (Q_SIGNED(q) ? (q) & ~Q_SRAWMASK(q) : (q))
#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)))
#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))))
#define Q_QLTQ(a, b) Q_QCMPQ(a, b, <, <)
#define Q_QLEQ(a, b) Q_QCMPQ(a, b, <, <=)
#define Q_QGTQ(a, b) Q_QCMPQ(a, b, >, >)
#define Q_QGEQ(a, b) Q_QCMPQ(a, b, >, >=)
#define Q_QEQ(a, b) Q_QCMPQ(a, b, ==, ==)
#define Q_QNEQ(a, b) Q_QCMPQ(a, b, !=, !=)
#define Q_QMAXQ(a, b) (Q_GT(a, b) ? (a) : (b))
#define Q_QMINQ(a, b) (Q_LT(a, b) ? (a) : (b))
#define Q_QCANREPQ(a, b) (( \
(!Q_LTZ(a) || Q_SIGNED(b)) \
&& ( Q_NIBITS(a) <= Q_NIBITS(b) \
|| 0 == (Q_GIABSVAL(a) & (~Q_TC(a, 0) << Q_NIBITS(b)))) \
&& ( Q_NFBITS(a) <= Q_NFBITS(b) \
|| 0 == (Q_GFABSVAL(a) & ~(~Q_TC(a, 0) << (Q_NFBITS(a) - Q_NFBITS(b))))) \
) ? 0 : EOVERFLOW)
#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)
#define Q_DEBUGFMT_(prefmt, postfmt, mod, hexpad) \
prefmt \
\
"\"%s\"@%p" \
\
"\n\ttype=%c%dq_t, " \
\
"Qm.n=Q%d.%d, " \
\
"rpshft=%d, " \
\
"imin=0x%0" #mod "x, " \
"imax=0x%0" #mod "x" \
\
"\n\tqraw=0x%0" #hexpad #mod "x" \
\
"\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" \
\
"\n\tiraw=0x%0" #hexpad #mod "x, " \
"iabsval=0x%" #mod "x, " \
"ival=0x%" #mod "x" \
\
"\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 \
#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:", "") : "" \
#define Q_NORMPREC(a, b) \
({ \
int _perr = 0, _relprec = Q_RELPREC(*(a), b); \
if (_relprec != 0) \
_perr = ERANGE; \
_perr; \
})
#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; \
})
#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); \
else if ((eop) == '+') { \
if (Q_IFMAXVAL(*(a)) - Q_GIFABSVAL(b) < Q_GIFVAL(*(a))) \
_aserr = EOVERFLOW; \
else \
Q_SIFVAL(*(a), Q_GIFVAL(*(a)) + Q_TC(*(a), \
Q_GIFABSVAL(b))); \
} else { \
if (Q_IFMINVAL(*(a)) + Q_GIFABSVAL(b) > Q_GIFVAL(*(a))) \
_aserr = EOVERFLOW; \
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); \
else if (Q_GIFABSVAL(b) == 0 || (!Q_SIGNED(*(a)) && Q_LTZ(b))) \
_err = EINVAL; \
\
else if (Q_GIFABSVAL(*(a)) != 0) { \
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); \
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; \
else if ((eop) == '+') { \
if (Q_IMAXVAL(*(q)) - Q_TC(*(q), Q_ABS(i)) < \
Q_GIVAL(*(q))) \
_aserr = EOVERFLOW; \
else \
Q_SIFVAL(*(q), Q_GIFVAL(*(q)) + \
Q_SHL(*(q), Q_ABS(i))); \
} else { \
if (Q_IMINVAL(*(q)) + Q_ABS(i) > Q_GIVAL(*(q))) \
_aserr = EOVERFLOW; \
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; \
else if (Q_GIFABSVAL(*(q)) != 0) { \
Q_SIFVAL(*(q), Q_GIFVAL(*(q)) / Q_TC(*(q), i)); \
if (Q_GIFABSVAL(*(q)) == 0) \
_diverr = ERANGE; \
} \
_diverr; \
})
#define Q_QMULI(q, i) \
({ \
int _mulerr = 0; \
if (!Q_SIGNED(*(q)) && Q_LTZ(i)) \
_mulerr = EINVAL; \
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; \
else if ((in) == 0) \
Q_SIFVAL(*(q), in); \
else if ((_tmp = Q_ABS(in)) > (UINT64_MAX >> Q_RPSHFT(*(q)))) \
_err = EOVERFLOW; \
else { \
_tmp = Q_SHL(*(q), _tmp) / Q_ABS(id); \
if (Q_QCANREPI(*(q), _tmp & Q_IFVALIMASK(*(q)))) \
_err = EOVERFLOW; \
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; \
} \
} \
_err; \
})
#endif